#pragma once

#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "UObject/ObjectMacros.h"
#if ALLOW_SIMPLYGON
THIRD_PARTY_INCLUDES_START
#include "Windows/AllowWindowsPlatformTypes.h"
#include "Simplygon.h"
#include "Windows/HideWindowsPlatformTypes.h"
THIRD_PARTY_INCLUDES_END
#endif // ALLOW_SIMPLYGON
#include "SimplygonUE4UI.generated.h"


/** Default visibility selection set name.*/
static const char* SG_VISIBILITY_SELECTION_SET_NAME = "CameraPointForVisibilitySet";

/** Default processing selection set name.*/
static const char* SG_PROCSSING_SELECTION_SET_NAME = "ObjectsToProcessSet";

/** Default clipping geometry selection set name.*/
static const char* SG_CLIPPING_GEOMETRY_SELECTION_SET_NAME = "ClippingGeometrySet"; 

/** Default occluder selection set name.*/
static const char* SG_OCCLUDER_GEOMETRY_SELECTION_SET_NAME = "OccludingGeometrySet"; 

/** Default material baking index.*/
static const int32 SG_MATERIALBAKING_INDEX = 137; 

/** Default clipping plane selection set name.*/
static const char* SG_CLIPPING_PLANES_SELECTION_SET_NAME = "ClippingPlanesSet";

/** Default UpVector.*/
static const FVector SimplygonIntegrationDefaultUp(0.0f,0.f,1.f);
/* Default ViewVector for Simplygon Integration */
static const FVector SimplygonIntegrationDefaultView(1.f, 0.f, 0.f);
/**
 * @brief The stop condition for the reducer.  Any -> the reducer will stop when any single one of the set reduction targets have been reached.  All -> the reducer will stop when all enabled reduction targets have been reached.
 */
UENUM(BlueprintType)
enum class EReductionTargetStopCondition : uint8
{
     /**
      * @brief Simplygon will stop as soon as one of the reduction targets has been fulfilled.
      */
     Any = 0,
     /**
      * @brief Simplygon will continue processing until all of the reduction targets have been fulfilled.
      */
     All = 1
};

static FString ToString(const EReductionTargetStopCondition DataFieldType)
{
     switch(DataFieldType)
     {
          case EReductionTargetStopCondition::Any: return "Any";
          case EReductionTargetStopCondition::All: return "All";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief The flag that decides how precise the reducer will be during the mesh reduction. Fast -> Reducer will be faster, but onscreensize and trianglecount will not match perfectly.  Consistent -> Reducer will be slower, but onscreensize and trianglecount will consistently give matching results.
 */
UENUM(BlueprintType)
enum class EReductionHeuristics : uint8
{
     /**
      * @brief Faster but with less precise calculations.
      */
     Fast = 0,
     /**
      * @brief Slower but more accurate.
      */
     Consistent = 1
};

static FString ToString(const EReductionHeuristics DataFieldType)
{
     switch(DataFieldType)
     {
          case EReductionHeuristics::Fast: return "Fast";
          case EReductionHeuristics::Consistent: return "Consistent";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief Set the reduction performance mode. Different performance modes dictates which features are available, and if a feature is enabled which is not compatible with the specified mode, the reducer will emit a warning, and run at a reduced performance. Please see the Concepts subsection of the documentation for which features are available in each mode.
 */
UENUM(BlueprintType)
enum class EReductionPerformanceMode : uint8
{
     /**
      * @brief All features available
      */
     AllFeatures = 0,
     /**
      * @brief Limited feature set but runs much faster.
      */
     HighPerformance = 1
};

static FString ToString(const EReductionPerformanceMode DataFieldType)
{
     switch(DataFieldType)
     {
          case EReductionPerformanceMode::AllFeatures: return "AllFeatures";
          case EReductionPerformanceMode::HighPerformance: return "HighPerformance";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief Set what axis to be used for symmetry calculations.
 */
UENUM(BlueprintType)
enum class ESymmetryAxis : uint8
{
     /**
      * @brief X axis.
      */
     X = 0,
     /**
      * @brief Z axis.
      */
     Y = 1,
     /**
      * @brief Z axis.
      */
     Z = 2
};

static FString ToString(const ESymmetryAxis DataFieldType)
{
     switch(DataFieldType)
     {
          case ESymmetryAxis::X: return "X";
          case ESymmetryAxis::Y: return "Y";
          case ESymmetryAxis::Z: return "Z";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief The flag that specifies how big 'freedom' Simplygon has when it comes to altering vertex/triangle data. Allowing more altered data means it will be easier to create good looking LODs, but without altered data it will be easier to keep the memory-usage in the LOD-chain more optimized. Note: When using OnlyUseOriginalData, the geometry being reduced can not have a node transformation matrix other than the identity matrix.
 */
UENUM(BlueprintType)
enum class EDataCreationPreferences : uint8
{
     /**
      * @brief Vertex and Corner data such as coordinates and normals will be completely re-used from the original Scene.
      */
     OnlyUseOriginalData = 0,
     /**
      * @brief Vertex coordinates will remaining as they were in the original Scene, but corner normals might be changed if Simplygon decided it will look better.
      */
     PreferOriginalData = 1,
     /**
      * @brief Both vertex coordinates and corner normals will be altered to make the optimized Scene look as good as possible.
      */
     PreferOptimizedResult = 2
};

static FString ToString(const EDataCreationPreferences DataFieldType)
{
     switch(DataFieldType)
     {
          case EDataCreationPreferences::OnlyUseOriginalData: return "OnlyUseOriginalData";
          case EDataCreationPreferences::PreferOriginalData: return "PreferOriginalData";
          case EDataCreationPreferences::PreferOptimizedResult: return "PreferOptimizedResult";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief Specifies the renderer type when computing visibility.
 */
UENUM(BlueprintType)
enum class EComputeVisibilityMode : uint8
{
     /**
      * @brief Use DirectX when computing visibility.
      */
     DirectX = 0,
     /**
      * @brief Use a software renderer when computing visibility.
      */
     Software = 1
};

static FString ToString(const EComputeVisibilityMode DataFieldType)
{
     switch(DataFieldType)
     {
          case EComputeVisibilityMode::DirectX: return "DirectX";
          case EComputeVisibilityMode::Software: return "Software";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief The stop condition for the bone reducer. Any: the reducer will stop when any single one of the set reduction targets have been reached. All: the reducer will stop when all enabled reduction targets have been set.
 */
UENUM(BlueprintType)
enum class EBoneReductionTargetStopCondition : uint8
{
     /**
      * @brief Simplygon will stop as soon as one of the reduction targets has been fulfilled.
      */
     Any = 0,
     /**
      * @brief Simplygon will continue processing until all of the reduction targets have been fulfilled.
      */
     All = 1
};

static FString ToString(const EBoneReductionTargetStopCondition DataFieldType)
{
     switch(DataFieldType)
     {
          case EBoneReductionTargetStopCondition::Any: return "Any";
          case EBoneReductionTargetStopCondition::All: return "All";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief If converting vertex colors to weights, this setting controls which color component is used to create the weights.
 */
UENUM(BlueprintType)
enum class EWeightsFromColorComponent : uint8
{
     /**
      * @brief Red color component
      */
     Red = 0,
     /**
      * @brief Green color component
      */
     Green = 1,
     /**
      * @brief Blue color component
      */
     Blue = 2,
     /**
      * @brief Alpha color component
      */
     Alpha = 3
};

static FString ToString(const EWeightsFromColorComponent DataFieldType)
{
     switch(DataFieldType)
     {
          case EWeightsFromColorComponent::Red: return "Red";
          case EWeightsFromColorComponent::Green: return "Green";
          case EWeightsFromColorComponent::Blue: return "Blue";
          case EWeightsFromColorComponent::Alpha: return "Alpha";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief If converting vertex colors to weights, this setting along with WeightsFromColorMultiplier controls how to map the RGBA intensity between 0-1 to weights. Standard mode maps color intensity [0-1] to vertex weight [1/Multiplier - Multiplier]. High mode maps color intensity [0-1] to vertex weight [1 - Multiplier]. Low mode maps color intensity [0-1] to vertex weight [1/Multiplier - 1].
 */
UENUM(BlueprintType)
enum class EWeightsFromColorMode : uint8
{
     /**
      * @brief Maps color intensity [0-1] to vertex weight [1/Multiplier - Multiplier]
      */
     Standard = 0,
     /**
      * @brief Maps color intensity [0-1] to vertex weight [1 - Multiplier]
      */
     High = 1,
     /**
      * @brief Maps color intensity [0-1] to vertex weight [1/Multiplier - 1]
      */
     Low = 2
};

static FString ToString(const EWeightsFromColorMode DataFieldType)
{
     switch(DataFieldType)
     {
          case EWeightsFromColorMode::Standard: return "Standard";
          case EWeightsFromColorMode::High: return "High";
          case EWeightsFromColorMode::Low: return "Low";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief Setting how Simplygon is to calculate or set the tessellation levels for per-triangle regular tessellated attributes.
 */
UENUM(BlueprintType)
enum class EAttributeTessellationDensityMode : uint8
{
     /**
      * @brief Base tessellation density on the relative area of the tessellated attribute, as a fraction of the total area of the surface of the scene, which is normalized to 1. Scenes will end up with roughly the same number of values, regardless of the scale of the scene, and regardless of the surface area of the geometries of scene.
      */
     RelativeArea = 0,
     /**
      * @brief Base tessellation density on the absolute area of the tessellated attribute. This will tessellate all attribute values the same size, and tessellated scaled up objects more than the same object scaled down.
      */
     AbsoluteArea = 1,
     /**
      * @brief Base tessellation density on the relative longest edge of the tessellated attribute, as a fraction of the total diagonal of the scene, which is normalized to 1. This will tessellate scenes the same, regardless of the scale, but scenes with more surface area will end up with a greater number of tessellated values than a scene with a smaller surface area.
      */
     RelativeLength = 2,
     /**
      * @brief Base tessellation density on the absolute longest edge of the tessellated attribute. This will tessellate all attribute values the same size, and tessellated scaled up objects more than the same object scaled down. More slivery triangles will be relatively more tessellated than equal area isotropic triangles, since their length to area ratio is higher.
      */
     AbsoluteLength = 3,
     /**
      * @brief User defined tessellation density. Tessellation levels are defined in a custom field named PrimitiveTessellationLevel. Note that this mode is only available in manual tessellation, and not as part of an automatic tessellation in processors or pipelines.
      */
     UserDefined = 4
};

static FString ToString(const EAttributeTessellationDensityMode DataFieldType)
{
     switch(DataFieldType)
     {
          case EAttributeTessellationDensityMode::RelativeArea: return "RelativeArea";
          case EAttributeTessellationDensityMode::AbsoluteArea: return "AbsoluteArea";
          case EAttributeTessellationDensityMode::RelativeLength: return "RelativeLength";
          case EAttributeTessellationDensityMode::AbsoluteLength: return "AbsoluteLength";
          case EAttributeTessellationDensityMode::UserDefined: return "UserDefined";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief The transformation space the evaluation should be done in. Valid values are Global and Local.
 */
UENUM(BlueprintType)
enum class ETransformationSpace : uint8
{
     /**
      * @brief Transformation in scene global space
      */
     Global = 0,
     /**
      * @brief Transformation in object/geometry local space
      */
     Local = 1,
     /**
      * @brief Transformation in vertex/triangle tangent space
      */
     Tangent = 2,
     /**
      * @brief Transformation in view/camera space
      */
     View = 3
};

static FString ToString(const ETransformationSpace DataFieldType)
{
     switch(DataFieldType)
     {
          case ETransformationSpace::Global: return "Global";
          case ETransformationSpace::Local: return "Local";
          case ETransformationSpace::Tangent: return "Tangent";
          case ETransformationSpace::View: return "View";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief Determines which method to use when generating the texture coordinates. Parameterizer generate from scratch based on the geometry. ChartAggregator generate based on the original texture coordinates.
 */
UENUM(BlueprintType)
enum class ETexCoordGeneratorType : uint8
{
     /**
      * @brief Texture coordinates are generated from scratch based on the geometry.
      */
     Parameterizer = 0,
     /**
      * @brief Texture coordinates are generated based on the original texture coordinates.
      */
     ChartAggregator = 1
};

static FString ToString(const ETexCoordGeneratorType DataFieldType)
{
     switch(DataFieldType)
     {
          case ETexCoordGeneratorType::Parameterizer: return "Parameterizer";
          case ETexCoordGeneratorType::ChartAggregator: return "ChartAggregator";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief Determines which method to use when aggregating the UVs. TextureSizeProportions - Aggregated UV charts will be scaled to keep their relative pixel density relative to all other UV charts. The user can still set the size of the output texture maps. SurfaceArea - Aggregated UV charts will have their size set based on its actual geometrical size. OriginalPixelDensity - The combined atlas will be resized to fit each chart so that all charts retain the same amount of pixels as they originally had. This will override any manually set texture size. UVSizeProportions - Aggregated UV charts will have their size set based on its original UV size, disregarding the size of the texture they are used in.
 */
UENUM(BlueprintType)
enum class EChartAggregatorMode : uint8
{
     /**
      * @brief Aggregated UV charts will be scaled to keep their relative pixel density relative to all other UV charts. The user can still set the size of the output texture maps.
      */
     TextureSizeProportions = 0,
     /**
      * @brief Aggregated UV charts will have their size set based on its actual geometrical size.
      */
     SurfaceArea = 1,
     /**
      * @brief The combined atlas will be resized to fit each chart so that all charts retain the same amount of pixels as they originally had. This will override any manually set texture size.
      */
     OriginalPixelDensity = 2,
     /**
      * @brief Aggregated UV charts will have their size set based on its original UV size, disregarding the size of the texture they are used in.
      */
     UVSizeProportions = 3
};

static FString ToString(const EChartAggregatorMode DataFieldType)
{
     switch(DataFieldType)
     {
          case EChartAggregatorMode::TextureSizeProportions: return "TextureSizeProportions";
          case EChartAggregatorMode::SurfaceArea: return "SurfaceArea";
          case EChartAggregatorMode::OriginalPixelDensity: return "OriginalPixelDensity";
          case EChartAggregatorMode::UVSizeProportions: return "UVSizeProportions";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief If multiple UV charts overlap and have the same material, SurfaceAreaScale specifies which of those instances determines the the output scale. It is only valid when the ChartAggregatorMode is SurfaceArea and SeparateOverlappingCharts is false.
 */
UENUM(BlueprintType)
enum class ESurfaceAreaScale : uint8
{
     /**
      * @brief If multiple UV charts overlap and have the same material, the largest instance determines the output scale. It is only valid when the ChartAggregatorMode is SurfaceArea and SeparateOverlappingCharts is false.
      */
     LargestInstance = 0,
     /**
      * @brief If multiple UV charts overlap and have the same material, the smallest instance determines the output scale. It is only valid when the ChartAggregatorMode is SurfaceArea and SeparateOverlappingCharts is false.
      */
     SmallestInstance = 1,
     /**
      * @brief If multiple UV charts overlap and have the same material, the average of all the instances determine the output scale. It is only valid when the ChartAggregatorMode is SurfaceArea and SeparateOverlappingCharts is false.
      */
     Average = 2
};

static FString ToString(const ESurfaceAreaScale DataFieldType)
{
     switch(DataFieldType)
     {
          case ESurfaceAreaScale::LargestInstance: return "LargestInstance";
          case ESurfaceAreaScale::SmallestInstance: return "SmallestInstance";
          case ESurfaceAreaScale::Average: return "Average";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief HoleFilling defines how aggressively the remesher will fill holes and cavities. What this does is to measure the volume and hole opening sizes of concavities in the input geometry and fill them in in the remeshing if the concavity is large enough with a small enough opening. This removes a lot of unnecessary geometry and is recommended to be kept at it's default rather than turning it off, it will in the vast majority of cases have a positive effect on the result.
 */
UENUM(BlueprintType)
enum class EHoleFilling : uint8
{
     /**
      * @brief No hole filling.
      */
     Disabled = 0,
     /**
      * @brief Minor hole filling.
      */
     Low = 1,
     /**
      * @brief Moderate amounts of hole filling.
      */
     Medium = 2,
     /**
      * @brief Aggressive hole filling.
      */
     High = 3
};

static FString ToString(const EHoleFilling DataFieldType)
{
     switch(DataFieldType)
     {
          case EHoleFilling::Disabled: return "Disabled";
          case EHoleFilling::Low: return "Low";
          case EHoleFilling::Medium: return "Medium";
          case EHoleFilling::High: return "High";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief The remeshing mode, options are Outside, Inside and Manual. RemeshingMode defines if the remeshing processor remeshes the outside or the inside of the input geometry. Manual needs the user to define a position in space that will be considered as outside for the purposes of the remeshing. Position is set with RemeshingModeManualPosition. Hole filling only works with the mode Outside.
 */
UENUM(BlueprintType)
enum class ERemeshingMode : uint8
{
     /**
      * @brief Automatically remeshes the outside of the geometry.
      */
     Outside = 0,
     /**
      * @brief Automatically remeshes the largest inside space of the geometry
      */
     Inside = 1,
     /**
      * @brief User defines a position in space that will be considered as outside for the purposes of the remeshing. Position is set with RemeshingModeManualPosition
      */
     Manual = 2
};

static FString ToString(const ERemeshingMode DataFieldType)
{
     switch(DataFieldType)
     {
          case ERemeshingMode::Outside: return "Outside";
          case ERemeshingMode::Inside: return "Inside";
          case ERemeshingMode::Manual: return "Manual";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief The surface transfer mode.
 */
UENUM(BlueprintType)
enum class ESurfaceTransferMode : uint8
{
     /**
      * @brief Faster but with less precise calculations.
      */
     Fast = 0,
     /**
      * @brief Slower and more accurate.
      */
     Accurate = 1
};

static FString ToString(const ESurfaceTransferMode DataFieldType)
{
     switch(DataFieldType)
     {
          case ESurfaceTransferMode::Fast: return "Fast";
          case ESurfaceTransferMode::Accurate: return "Accurate";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief Specifies how the impostors should be mapped to the scene.
 */
UENUM(BlueprintType)
enum class EBillboardMode : uint8
{
     /**
      * @brief Prioritize fitting the impostors to the exterior hull of the scene. Better for solid/opaque meshes like buildings/vehicles.
      */
     OuterShell = 0,
     /**
      * @brief The impostors fit to the entire volume of the scene. Better for chaotic meshes that has lots of geometry within its volume, like vegetation.
      */
     Foliage = 1
};

static FString ToString(const EBillboardMode DataFieldType)
{
     switch(DataFieldType)
     {
          case EBillboardMode::OuterShell: return "OuterShell";
          case EBillboardMode::Foliage: return "Foliage";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief The stop condition for the reducer to finish processing. Any -> the reducer will stop when any single one of the set reduction targets have been reached. All -> the reducer will stop when all enabled reduction targets have been reached.
 */
UENUM(BlueprintType)
enum class EStopCondition : uint8
{
     /**
      * @brief Simplygon will stop as soon as one of the reduction targets has been fulfilled.
      */
     Any = 0,
     /**
      * @brief Simplygon will continue processing until all of the reduction targets have been fulfilled.
      */
     All = 1
};

static FString ToString(const EStopCondition DataFieldType)
{
     switch(DataFieldType)
     {
          case EStopCondition::Any: return "Any";
          case EStopCondition::All: return "All";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief The component in the opacity channel to use as opacity value.
 */
UENUM(BlueprintType)
enum class EOpacityChannelComponent : uint8
{
     /**
      * @brief Red color component
      */
     Red = 0,
     /**
      * @brief Green color component
      */
     Green = 1,
     /**
      * @brief Blue color component
      */
     Blue = 2,
     /**
      * @brief Alpha color component
      */
     Alpha = 3
};

static FString ToString(const EOpacityChannelComponent DataFieldType)
{
     switch(DataFieldType)
     {
          case EOpacityChannelComponent::Red: return "Red";
          case EOpacityChannelComponent::Green: return "Green";
          case EOpacityChannelComponent::Blue: return "Blue";
          case EOpacityChannelComponent::Alpha: return "Alpha";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief The type of dithering to use when creating the output object.
 */
UENUM(BlueprintType)
enum class EDitherType : uint8
{
     /**
      * @brief Use no dithering
      */
     NoDither = 0,
     /**
      * @brief Use Floyd-Steinberg dithering
      */
     FloydSteinberg = 1,
     /**
      * @brief Use Jarvis, Judice, and Ninke dithering
      */
     JarvisJudiceNinke = 2,
     /**
      * @brief Use Sierra-3 (three row) dithering
      */
     Sierra = 3
};

static FString ToString(const EDitherType DataFieldType)
{
     switch(DataFieldType)
     {
          case EDitherType::NoDither: return "NoDither";
          case EDitherType::FloydSteinberg: return "FloydSteinberg";
          case EDitherType::JarvisJudiceNinke: return "JarvisJudiceNinke";
          case EDitherType::Sierra: return "Sierra";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation.
 */
UENUM(BlueprintType)
enum class EFillMode : uint8
{
     /**
      * @brief linearly interpolate the closest samples
      */
     Interpolate = 0,
     /**
      * @brief use the closest available pixel value without interpolation
      */
     NearestNeighbor = 1,
     /**
      * @brief Do not fill remaining pixels
      */
     NoFill = 2
};

static FString ToString(const EFillMode DataFieldType)
{
     switch(DataFieldType)
     {
          case EFillMode::Interpolate: return "Interpolate";
          case EFillMode::NearestNeighbor: return "NearestNeighbor";
          case EFillMode::NoFill: return "NoFill";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief File format for output texture.
 */
UENUM(BlueprintType)
enum class EOutputImageFileFormat : uint8
{
     /**
      * @brief 
      */
     BMP = 0,
     /**
      * @brief 
      */
     DDS = 1,
     /**
      * @brief 
      */
     JPEG = 2,
     /**
      * @brief 
      */
     PNG = 3,
     /**
      * @brief 
      */
     TGA = 4,
     /**
      * @brief 
      */
     TIFF = 5,
     /**
      * @brief 
      */
     EXR = 8
};

static FString ToString(const EOutputImageFileFormat DataFieldType)
{
     switch(DataFieldType)
     {
          case EOutputImageFileFormat::BMP: return "BMP";
          case EOutputImageFileFormat::DDS: return "DDS";
          case EOutputImageFileFormat::JPEG: return "JPEG";
          case EOutputImageFileFormat::PNG: return "PNG";
          case EOutputImageFileFormat::TGA: return "TGA";
          case EOutputImageFileFormat::TIFF: return "TIFF";
          case EOutputImageFileFormat::EXR: return "EXR";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief DDS compression if output format is DDS.
 */
UENUM(BlueprintType)
enum class EOutputDDSCompressionType : uint8
{
     /**
      * @brief 
      */
     NoCompression = 255,
     /**
      * @brief 
      */
     BC1 = 0,
     /**
      * @brief 
      */
     BC2 = 1,
     /**
      * @brief 
      */
     BC3 = 2,
     /**
      * @brief 
      */
     BC4 = 3,
     /**
      * @brief 
      */
     BC5 = 4
};

static FString ToString(const EOutputDDSCompressionType DataFieldType)
{
     switch(DataFieldType)
     {
          case EOutputDDSCompressionType::NoCompression: return "NoCompression";
          case EOutputDDSCompressionType::BC1: return "BC1";
          case EOutputDDSCompressionType::BC2: return "BC2";
          case EOutputDDSCompressionType::BC3: return "BC3";
          case EOutputDDSCompressionType::BC4: return "BC4";
          case EOutputDDSCompressionType::BC5: return "BC5";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief The opacity type determines how the opacity channel of this material should be saved. To make (0.0->1.0) map to (transparent-opaque), use 'Opacity'. To make (0.0->1.0) map to (opaque-transparent), use 'Transparency'
 */
UENUM(BlueprintType)
enum class EOutputOpacityType : uint8
{
     /**
      * @brief The level of transparency is defined from 0.0->1.0, where 0.0 is fully transparent and 1.0 is fully opaque.
      */
     Opacity = 0,
     /**
      * @brief The level of transparency is defined from 1.0->0.0, where 1.0 is fully transparent and 0.0 is fully opaque.
      */
     Transparency = 1
};

static FString ToString(const EOutputOpacityType DataFieldType)
{
     switch(DataFieldType)
     {
          case EOutputOpacityType::Opacity: return "Opacity";
          case EOutputOpacityType::Transparency: return "Transparency";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief The output pixel format
 */
UENUM(BlueprintType)
enum class EOutputPixelFormat : uint8
{
     /**
      * @brief RGBA color channels with 8 bit depth per color channel
      */
     R8G8B8A8 = 0,
     /**
      * @brief RGB color channels with 8 bit depth per color channel
      */
     R8G8B8 = 1,
     /**
      * @brief R color channel with 8 bit depth per color channel
      */
     R8 = 2,
     /**
      * @brief RGBA color channels with 16 bit depth per color channel
      */
     R16G16B16A16 = 3,
     /**
      * @brief RGB color channels with 16 bit depth per color channel
      */
     R16G16B16 = 4,
     /**
      * @brief R color channel with 16 bit depth per color channel
      */
     R16 = 5,
     /**
      * @brief RGBA color channels with 32 bit depth floating point per color channel
      */
     R32G32B32A32F = 6
};

static FString ToString(const EOutputPixelFormat DataFieldType)
{
     switch(DataFieldType)
     {
          case EOutputPixelFormat::R8G8B8A8: return "R8G8B8A8";
          case EOutputPixelFormat::R8G8B8: return "R8G8B8";
          case EOutputPixelFormat::R8: return "R8";
          case EOutputPixelFormat::R16G16B16A16: return "R16G16B16A16";
          case EOutputPixelFormat::R16G16B16: return "R16G16B16";
          case EOutputPixelFormat::R16: return "R16";
          case EOutputPixelFormat::R32G32B32A32F: return "R32G32B32A32F";
          default: return "UnknownDataFieldType";
     }
}

/**
 * @brief The GeometryDataFieldType setting, which specifies what field type to cast in the GeometryDataCaster.
 */
UENUM(BlueprintType)
enum class EGeometryDataFieldType : uint8
{
     /**
      * @brief Per-vertex coordinate data, xyz values (3 items per tuple, default attribute format type F32vec3)
      */
     Coords = 0,
     /**
      * @brief Per-corner texture coords data, uv values (2 items per tuple, default attribute format type F32vec2)
      */
     TexCoords = 1,
     /**
      * @brief Per-corner vertex normals data, xyz values (3 items per tuple, default attribute format type F32vec3)
      */
     Normals = 2,
     /**
      * @brief Per-corner vertex tangent data, xyz values (3 items per tuple, default attribute format type F32vec3)
      */
     Tangents = 3,
     /**
      * @brief Per-corner vertex bitangent data, xyz values (3 items per tuple, default attribute format type F32vec3)
      */
     Bitangents = 4,
     /**
      * @brief Per-corner vertex color data, rgba values (4 items per tuple, default attribute format type F32vec4)
      */
     Colors = 5,
     /**
      * @brief Per-triangle triangle ids, id values, not interpolated. (1 item per tuple, default attribute format type S32)
      */
     TriangleIds = 6,
     /**
      * @brief Per-triangle material ids, id values, not interpolated. (1 item per tuple, default attribute format type S32)
      */
     MaterialIds = 7,
     /**
      * @brief Per-corner vertex ids, id values, not interpolated. (1 item per tuple, default attribute format type S32)
      */
     VertexIds = 8,
     /**
      * @brief User-defined Per-vertex geometry data field.
      */
     UserVertexField = 9,
     /**
      * @brief User-defined Per-corner geometry data field.
      */
     UserCornerField = 10,
     /**
      * @brief User-defined Per-triangle geometry data field.
      */
     UserTriangleField = 11,
     /**
      * @brief Custom-size user-defined geometry data field.
      */
     CustomField = 12
};

static FString ToString(const EGeometryDataFieldType DataFieldType)
{
     switch(DataFieldType)
     {
          case EGeometryDataFieldType::Coords: return "Coords";
          case EGeometryDataFieldType::TexCoords: return "TexCoords";
          case EGeometryDataFieldType::Normals: return "Normals";
          case EGeometryDataFieldType::Tangents: return "Tangents";
          case EGeometryDataFieldType::Bitangents: return "Bitangents";
          case EGeometryDataFieldType::Colors: return "Colors";
          case EGeometryDataFieldType::TriangleIds: return "TriangleIds";
          case EGeometryDataFieldType::MaterialIds: return "MaterialIds";
          case EGeometryDataFieldType::VertexIds: return "VertexIds";
          case EGeometryDataFieldType::UserVertexField: return "UserVertexField";
          case EGeometryDataFieldType::UserCornerField: return "UserCornerField";
          case EGeometryDataFieldType::UserTriangleField: return "UserTriangleField";
          case EGeometryDataFieldType::CustomField: return "CustomField";
          default: return "UnknownDataFieldType";
     }
}


UCLASS(DefaultToInstanced, abstract, editinlinenew)
class SIMPLYGONUOBJECTS_API USimplygonPipeline : public UObject
{
    GENERATED_BODY()

public:
    virtual bool HasValidSettings(FString& ErrorMsg) const { return true; }

#if ALLOW_SIMPLYGON
    virtual Simplygon::spPipeline CreatePipeline(Simplygon::ISimplygon* simplygon) { return Simplygon::NullPtr; };
#endif

};


USTRUCT()
struct SIMPLYGONUOBJECTS_API FSimplygonPipelineSettings
{
    GENERATED_BODY()

public:
    virtual ~FSimplygonPipelineSettings() {}
#if ALLOW_SIMPLYGON
    virtual Simplygon::spPipeline CreatePipeline(Simplygon::ISimplygon* simplygon) { return Simplygon::NullPtr; };
#endif

};


UCLASS(DefaultToInstanced, abstract, editinlinenew)
class SIMPLYGONUOBJECTS_API USimplygonMaterialCaster : public UObject
{
    GENERATED_BODY()

public:
#if ALLOW_SIMPLYGON
    virtual Simplygon::spMaterialCaster CreateMaterialCaster(Simplygon::ISimplygon* simplygon) { return Simplygon::NullPtr; };
#endif

};

USTRUCT(BlueprintType, Blueprintable)
struct FReductionSettings
{
    GENERATED_USTRUCT_BODY()

/** Enable triangle ratio as a reduction target. The reducer will stop when the set triangle-ratio has been reached. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    uint8 ReductionTargetTriangleRatioEnabled:1;

/** The wanted reduction ratio. The range is 0->1. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    float ReductionTargetTriangleRatio;

/** Enable triangle count as a reduction target. The reducer will stop when the set triangle count has been reached. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    uint8 ReductionTargetTriangleCountEnabled:1;

/** The wanted triangle count. The range is 0->inf. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    int32 ReductionTargetTriangleCount;

/** Enable max deviation as a reduction target. The reducer will stop when the set max deviation has been reached. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    uint8 ReductionTargetMaxDeviationEnabled:1;

/** The MaxDeviation value, the maximum surface-deviation between the reduced geometry and the original. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    float ReductionTargetMaxDeviation;

/** Enable on screen size as a reduction target. The reducer will stop when the set on screen size has been reached. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    uint8 ReductionTargetOnScreenSizeEnabled:1;

/** The OnScreenSize value, used to calculate the maximum surface-deviation allowed, by assuming errors less than 1 pixel onscreen will not be noticeable. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    int32 ReductionTargetOnScreenSize;

/** The stop condition for the reducer.  Any -> the reducer will stop when any single one of the set reduction targets have been reached.  All -> the reducer will stop when all enabled reduction targets have been reached. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    EReductionTargetStopCondition ReductionTargetStopCondition;

/** The flag that decides how precise the reducer will be during the mesh reduction. Fast -> Reducer will be faster, but onscreensize and trianglecount will not match perfectly.  Consistent -> Reducer will be slower, but onscreensize and trianglecount will consistently give matching results. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    EReductionHeuristics ReductionHeuristics;

/** Set the reduction performance mode. Different performance modes dictates which features are available, and if a feature is enabled which is not compatible with the specified mode, the reducer will emit a warning, and run at a reduced performance. Please see the Concepts subsection of the documentation for which features are available in each mode. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    EReductionPerformanceMode ReductionPerformanceMode;

/** The importance value of the position of the vertices and triangles of the Geometry, or the silhouette of the Geometry. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0 */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    float GeometryImportance;

/** The importance value of the boundary between triangles with different materials. For example, if triangles with a metallic material are connected to triangles with a wood material, this setting will determine how important it is to keep the border between them intact. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0 */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    float MaterialImportance;

/** The importance value of the UV coordinates of the Geometry, both the boundary of the UV charts, as well as the UV stretch across the triangles. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0 */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    float TextureImportance;

/** The importance value of the vertex-normals of the Geometry, both the sharp edges, as well as how the normals interpolate over the surface of the triangles. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0 */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    float ShadingImportance;

/** The importance value of the boundary between triangles from different sub-geometries. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0 */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    float GroupImportance;

/** The importance value of the vertex-colors of the Geometry, both the boundary between triangles with different colors, as well as how the colors interpolate over the surface of the triangles. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0 */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    float VertexColorImportance;

/** The importance value of user selected edges. Can be used when a Boolean UserCornerField with the name SgEdgeSelectionSet is added to the Geometry. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0 */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    float EdgeSetImportance;

/** The importance value of the bone-weights of the vertices. The more impact a vertex has on the skinning of the Geometry (for example, vertices close to joints), the more likely it is to be kept. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0 */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    float SkinningImportance;

/** The CreateGeomorphGeometry value. If set, the reducer will create a GeometryData object that is a morphed version of the original GeometryData, that can be used to morph between the original geometry and the reduced geometry. Should not be used together with TJunctionRemover, NormalRecalculation or Material LOD. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    uint8 CreateGeomorphGeometry:1;

/** The AllowDegenerateTexCoords flag. If true, texture coordinates are allowed to become degenerate (triangles can have 0 area in texture space). This may sometimes look better, but if tangent space normals are used, tangent spaces may become degenerate. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    uint8 AllowDegenerateTexCoords:1;

/** The KeepSymmetry flag. If set, the reducer will detect symmetric features, and retain symmetry during processing. Please note that for a geometry to be considered symmetrical, also the texture coordinates must be mirrored. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    uint8 KeepSymmetry:1;

/** The AutomaticSymmetryDetection flag. If set, and KeepSymmetry is on, the reducer will detect any X,Y,Z symmetry plane and will override any user set symmetry plane with the detected one. If no symmetry is found, KeepSymmetry will be turned off before reduction. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    uint8 UseAutomaticSymmetryDetection:1;

/** The UseSymmetryQuadRetriangulator flag. If true, and KeepSymmetry is on, any triangles that have been triangulated from symmetrical quads into unsymmetrical triangles are detected and fixed. The edges of said triangles are flipped across the old quad so that the mesh becomes symmetrical again. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    uint8 UseSymmetryQuadRetriangulator:1;

/** Set what axis to be used for symmetry calculations. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    ESymmetryAxis SymmetryAxis;

/** Set SymmetryOffset, the position on the symmetry axis where the symmetry plane is placed. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    float SymmetryOffset;

/** The tolerance used when detecting symmetry. Values in the ranges 1e-5 to 1e-3 will usually produce good results. This specific tolerance corresponds to the off-plane tolerance, ie. the tolerance of the coordinate components that are not the symmetry axis. The in-plane tolerance is always 10 times the off-plane tolerance. This value is relative to the size of the Geometry, so 0.01 would mean 1% of the bounding box size of the Geometry. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    float SymmetryDetectionTolerance;

/** The flag that specifies how big 'freedom' Simplygon has when it comes to altering vertex/triangle data. Allowing more altered data means it will be easier to create good looking LODs, but without altered data it will be easier to keep the memory-usage in the LOD-chain more optimized. Note: When using OnlyUseOriginalData, the geometry being reduced can not have a node transformation matrix other than the identity matrix. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    EDataCreationPreferences DataCreationPreferences;

/** The flag for if the reduction process should store geomorph data in the processed GeometryData object. This data is an array with same size as the vertexcount was before the reduction process, and will have the coordinates for each vertex on its corresponding position on the reduced GeometryData surface. Can be used to give smooth transition from a highlevel LOD to a lowlevel LOD. This array can be accessed with the GeometryData custom field 'SgMappedVertexCoords'. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    uint8 GenerateGeomorphData:1;

/** The outward move multiplier, how much the mesh is allowed to grow its silhouette perimeter. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    float OutwardMoveMultiplier;

/** The inward move multiplier, how much the mesh is allowed to shrink its silhouette perimeter. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    float InwardMoveMultiplier;

/** The maximum length of the triangles edges after reduction. Can be used to limit output triangle size. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    float MaxEdgeLength;

/** Set to true and the reducer will do a much more precise way of calculating the vertex normals. It will however be slower. Set to false and it will do a much more rough estimation of what the vertex normals will look like, but faster. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    uint8 UseHighQualityNormalCalculation:1;

/** Which selection set should be processed. If set to -1, all geometries in the scene will be processed. If both selection set name and ID are set, the name will be used. */
    UPROPERTY()
    int32 ProcessSelectionSetID;

/** Which selection set should be processed. If the name is not found, all geometries in the scene will be processed. If both selection set name and ID are set, the name will be used. */
    UPROPERTY()
    FString ProcessSelectionSetName;

/** The processor will merge all the geometries in the scene into a single geometry if MergeGeometries is enabled. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    uint8 MergeGeometries:1;

/** If false, the processor will remove all geometry and scene meshes which were not selected for processing from the scene. If true, only the geometry in the ProcessSelectionSet will be replaced or updated, while the rest of the scene tree is kept intact. New geometry is always added as the last child of the scene root. If generating a mappingimage to cast materials, new materialIds will also be appended to the end of the old material table instead of replacing the old ones. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    uint8 KeepUnprocessedSceneMeshes:1;

/** If set, will lock the geometric border of the geometry, and not reduce at all. This setting might be useful if the geometry needs to fit a neighbor geometry, but will reduce overall reduction quality (geometric quality over reduction ratio) */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    uint8 LockGeometricBorder:1;

/** If true, the QuadFlags triangle field in the input geometries (used for marking triangle pairs as quads for use in the QuadReductionProcessor) will be maintained in the processing geometries through the triangle reduction process as well as possible. This will cause most polygons involved in collapses performed by the triangle reducer to become triangles. This allows sequential triangle->quad reductions to handle mixed geometries. Setting this to false removes the QuadFlags triangle field entirely, ensuring the output geometry is 100% triangles with no implicit quads. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ReductionSettings)
    uint8 PreserveQuadFlags:1;

    FReductionSettings() :
        ReductionTargetTriangleRatioEnabled(true),
        ReductionTargetTriangleRatio(0.5),
        ReductionTargetTriangleCountEnabled(false),
        ReductionTargetTriangleCount(10000),
        ReductionTargetMaxDeviationEnabled(false),
        ReductionTargetMaxDeviation(1),
        ReductionTargetOnScreenSizeEnabled(false),
        ReductionTargetOnScreenSize(300),
        ReductionTargetStopCondition(EReductionTargetStopCondition::All),
        ReductionHeuristics(EReductionHeuristics::Fast),
        ReductionPerformanceMode(EReductionPerformanceMode::AllFeatures),
        GeometryImportance(1),
        MaterialImportance(1),
        TextureImportance(1),
        ShadingImportance(1),
        GroupImportance(1),
        VertexColorImportance(1),
        EdgeSetImportance(1),
        SkinningImportance(1),
        CreateGeomorphGeometry(false),
        AllowDegenerateTexCoords(true),
        KeepSymmetry(false),
        UseAutomaticSymmetryDetection(false),
        UseSymmetryQuadRetriangulator(true),
        SymmetryAxis(ESymmetryAxis::X),
        SymmetryOffset(0),
        SymmetryDetectionTolerance(0.0001),
        DataCreationPreferences(EDataCreationPreferences::PreferOptimizedResult),
        GenerateGeomorphData(false),
        OutwardMoveMultiplier(1),
        InwardMoveMultiplier(1),
        MaxEdgeLength(3.402823E+38),
        UseHighQualityNormalCalculation(true),
        ProcessSelectionSetID(-1),
        ProcessSelectionSetName(""),
        MergeGeometries(false),
        KeepUnprocessedSceneMeshes(false),
        LockGeometricBorder(false),
        PreserveQuadFlags(true)
    {
    }

    FReductionSettings(const FReductionSettings& Other) :
        ReductionTargetTriangleRatioEnabled(Other.ReductionTargetTriangleRatioEnabled),
        ReductionTargetTriangleRatio(Other.ReductionTargetTriangleRatio),
        ReductionTargetTriangleCountEnabled(Other.ReductionTargetTriangleCountEnabled),
        ReductionTargetTriangleCount(Other.ReductionTargetTriangleCount),
        ReductionTargetMaxDeviationEnabled(Other.ReductionTargetMaxDeviationEnabled),
        ReductionTargetMaxDeviation(Other.ReductionTargetMaxDeviation),
        ReductionTargetOnScreenSizeEnabled(Other.ReductionTargetOnScreenSizeEnabled),
        ReductionTargetOnScreenSize(Other.ReductionTargetOnScreenSize),
        ReductionTargetStopCondition(Other.ReductionTargetStopCondition),
        ReductionHeuristics(Other.ReductionHeuristics),
        ReductionPerformanceMode(Other.ReductionPerformanceMode),
        GeometryImportance(Other.GeometryImportance),
        MaterialImportance(Other.MaterialImportance),
        TextureImportance(Other.TextureImportance),
        ShadingImportance(Other.ShadingImportance),
        GroupImportance(Other.GroupImportance),
        VertexColorImportance(Other.VertexColorImportance),
        EdgeSetImportance(Other.EdgeSetImportance),
        SkinningImportance(Other.SkinningImportance),
        CreateGeomorphGeometry(Other.CreateGeomorphGeometry),
        AllowDegenerateTexCoords(Other.AllowDegenerateTexCoords),
        KeepSymmetry(Other.KeepSymmetry),
        UseAutomaticSymmetryDetection(Other.UseAutomaticSymmetryDetection),
        UseSymmetryQuadRetriangulator(Other.UseSymmetryQuadRetriangulator),
        SymmetryAxis(Other.SymmetryAxis),
        SymmetryOffset(Other.SymmetryOffset),
        SymmetryDetectionTolerance(Other.SymmetryDetectionTolerance),
        DataCreationPreferences(Other.DataCreationPreferences),
        GenerateGeomorphData(Other.GenerateGeomorphData),
        OutwardMoveMultiplier(Other.OutwardMoveMultiplier),
        InwardMoveMultiplier(Other.InwardMoveMultiplier),
        MaxEdgeLength(Other.MaxEdgeLength),
        UseHighQualityNormalCalculation(Other.UseHighQualityNormalCalculation),
        ProcessSelectionSetID(Other.ProcessSelectionSetID),
        ProcessSelectionSetName(Other.ProcessSelectionSetName),
        MergeGeometries(Other.MergeGeometries),
        KeepUnprocessedSceneMeshes(Other.KeepUnprocessedSceneMeshes),
        LockGeometricBorder(Other.LockGeometricBorder),
        PreserveQuadFlags(Other.PreserveQuadFlags)
    {}

    bool operator==(const FReductionSettings& Other) const
    {
        return
              ReductionTargetTriangleRatioEnabled == Other.ReductionTargetTriangleRatioEnabled &&
              ReductionTargetTriangleRatio == Other.ReductionTargetTriangleRatio &&
              ReductionTargetTriangleCountEnabled == Other.ReductionTargetTriangleCountEnabled &&
              ReductionTargetTriangleCount == Other.ReductionTargetTriangleCount &&
              ReductionTargetMaxDeviationEnabled == Other.ReductionTargetMaxDeviationEnabled &&
              ReductionTargetMaxDeviation == Other.ReductionTargetMaxDeviation &&
              ReductionTargetOnScreenSizeEnabled == Other.ReductionTargetOnScreenSizeEnabled &&
              ReductionTargetOnScreenSize == Other.ReductionTargetOnScreenSize &&
              ReductionTargetStopCondition == Other.ReductionTargetStopCondition &&
              ReductionHeuristics == Other.ReductionHeuristics &&
              ReductionPerformanceMode == Other.ReductionPerformanceMode &&
              GeometryImportance == Other.GeometryImportance &&
              MaterialImportance == Other.MaterialImportance &&
              TextureImportance == Other.TextureImportance &&
              ShadingImportance == Other.ShadingImportance &&
              GroupImportance == Other.GroupImportance &&
              VertexColorImportance == Other.VertexColorImportance &&
              EdgeSetImportance == Other.EdgeSetImportance &&
              SkinningImportance == Other.SkinningImportance &&
              CreateGeomorphGeometry == Other.CreateGeomorphGeometry &&
              AllowDegenerateTexCoords == Other.AllowDegenerateTexCoords &&
              KeepSymmetry == Other.KeepSymmetry &&
              UseAutomaticSymmetryDetection == Other.UseAutomaticSymmetryDetection &&
              UseSymmetryQuadRetriangulator == Other.UseSymmetryQuadRetriangulator &&
              SymmetryAxis == Other.SymmetryAxis &&
              SymmetryOffset == Other.SymmetryOffset &&
              SymmetryDetectionTolerance == Other.SymmetryDetectionTolerance &&
              DataCreationPreferences == Other.DataCreationPreferences &&
              GenerateGeomorphData == Other.GenerateGeomorphData &&
              OutwardMoveMultiplier == Other.OutwardMoveMultiplier &&
              InwardMoveMultiplier == Other.InwardMoveMultiplier &&
              MaxEdgeLength == Other.MaxEdgeLength &&
              UseHighQualityNormalCalculation == Other.UseHighQualityNormalCalculation &&
              ProcessSelectionSetID == Other.ProcessSelectionSetID &&
              ProcessSelectionSetName == Other.ProcessSelectionSetName &&
              MergeGeometries == Other.MergeGeometries &&
              KeepUnprocessedSceneMeshes == Other.KeepUnprocessedSceneMeshes &&
              LockGeometricBorder == Other.LockGeometricBorder &&
              PreserveQuadFlags == Other.PreserveQuadFlags;
    }

    bool operator!=(const FReductionSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FRepairSettings
{
    GENERATED_USTRUCT_BODY()

/** If set, t-junctions will be removed. If enabled, it also requires UseWelding to be on. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RepairSettings)
    uint8 UseTJunctionRemover:1;

/** The T-Junction distance, below which, the T-Junctions will be welded. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RepairSettings)
    float TJuncDist;

/** The welding distance below which the vertices will be welded. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RepairSettings)
    float WeldDist;

/** If set, only vertices that are on the border (as reported by the VertexBorder boolean field) are considered for the welding. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RepairSettings)
    uint8 WeldOnlyBorderVertices:1;

/** If set, only vertices that are within the same material are welded. Vertices on material borders are locked. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RepairSettings)
    uint8 WeldOnlyWithinMaterial:1;

/** If set, only vertices that are within the same scene node are welded. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RepairSettings)
    uint8 WeldOnlyWithinSceneNode:1;

/** If set, only vertices that belong to different scene nodes are considered for the welding. Affects both welder and t-junction remover. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RepairSettings)
    uint8 WeldOnlyBetweenSceneNodes:1;

/** If set, vertices within each others welding distance will be welded together. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RepairSettings)
    uint8 UseWelding:1;

/** The number of progressive passes. Minimum is 1, but higher numbers give a better quality, at the expense of longer running time. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RepairSettings)
    int32 ProgressivePasses;

    FRepairSettings() :
        UseTJunctionRemover(true),
        TJuncDist(0),
        WeldDist(0),
        WeldOnlyBorderVertices(false),
        WeldOnlyWithinMaterial(false),
        WeldOnlyWithinSceneNode(false),
        WeldOnlyBetweenSceneNodes(false),
        UseWelding(true),
        ProgressivePasses(3)
    {
    }

    FRepairSettings(const FRepairSettings& Other) :
        UseTJunctionRemover(Other.UseTJunctionRemover),
        TJuncDist(Other.TJuncDist),
        WeldDist(Other.WeldDist),
        WeldOnlyBorderVertices(Other.WeldOnlyBorderVertices),
        WeldOnlyWithinMaterial(Other.WeldOnlyWithinMaterial),
        WeldOnlyWithinSceneNode(Other.WeldOnlyWithinSceneNode),
        WeldOnlyBetweenSceneNodes(Other.WeldOnlyBetweenSceneNodes),
        UseWelding(Other.UseWelding),
        ProgressivePasses(Other.ProgressivePasses)
    {}

    bool operator==(const FRepairSettings& Other) const
    {
        return
              UseTJunctionRemover == Other.UseTJunctionRemover &&
              TJuncDist == Other.TJuncDist &&
              WeldDist == Other.WeldDist &&
              WeldOnlyBorderVertices == Other.WeldOnlyBorderVertices &&
              WeldOnlyWithinMaterial == Other.WeldOnlyWithinMaterial &&
              WeldOnlyWithinSceneNode == Other.WeldOnlyWithinSceneNode &&
              WeldOnlyBetweenSceneNodes == Other.WeldOnlyBetweenSceneNodes &&
              UseWelding == Other.UseWelding &&
              ProgressivePasses == Other.ProgressivePasses;
    }

    bool operator!=(const FRepairSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FNormalCalculationSettings
{
    GENERATED_USTRUCT_BODY()

/** If set, it will generate new normals for the Geometry, and if not set, it will keep the normals from the original normal set (or not add normals at all if none were present). Please note that if the original geometry contains normals, the normal repairer will replace invalid normals even if ReplaceNormals is set to false. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCalculationSettings)
    uint8 ReplaceNormals:1;

/** If set, it will generate new tangents and bitangents for the Geometry, and if not set, it will keep the new tangents and bitangents from the original normal set (or not add tangents and bitangents at all if none were present). */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCalculationSettings)
    uint8 ReplaceTangents:1;

/** Set HardEdgeAngle in degrees. If the angle between two triangles are above this value, the normals will not be smooth over the edge between those two triangles. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCalculationSettings)
    float HardEdgeAngle;

/** If set, normals that are invalid will be replaced. All others are left intact. Bad normals are those that are either zero length, or simply points away from the surface. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCalculationSettings)
    uint8 RepairInvalidNormals:1;

/** If set, the tangentspaces already existing in the scene will be readjusted so that the tangent and binormal are both orthogonal to the normal. Will be needed since most of the time the normals are changed in the reduction process. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCalculationSettings)
    uint8 ReorthogonalizeTangentSpace:1;

/** If set, the influence of a triangle normal upon the vertex normals is scaled by the area of the triangle. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCalculationSettings)
    uint8 ScaleByArea:1;

/** If set, the influence of a triangle normal upon the vertex normals is scaled by the angle of the corner at the vertex. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCalculationSettings)
    uint8 ScaleByAngle:1;

/** If set, perfectly flat shaded surfaces will be created, where possible. Normals adjacent to perfectly geometrically flat surfaces will be recalculated to have the same direction as for those of the adjacent flat surface. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCalculationSettings)
    uint8 SnapNormalsToFlatSurfaces:1;

    FNormalCalculationSettings() :
        ReplaceNormals(false),
        ReplaceTangents(false),
        HardEdgeAngle(75),
        RepairInvalidNormals(false),
        ReorthogonalizeTangentSpace(true),
        ScaleByArea(true),
        ScaleByAngle(true),
        SnapNormalsToFlatSurfaces(false)
    {
    }

    FNormalCalculationSettings(const FNormalCalculationSettings& Other) :
        ReplaceNormals(Other.ReplaceNormals),
        ReplaceTangents(Other.ReplaceTangents),
        HardEdgeAngle(Other.HardEdgeAngle),
        RepairInvalidNormals(Other.RepairInvalidNormals),
        ReorthogonalizeTangentSpace(Other.ReorthogonalizeTangentSpace),
        ScaleByArea(Other.ScaleByArea),
        ScaleByAngle(Other.ScaleByAngle),
        SnapNormalsToFlatSurfaces(Other.SnapNormalsToFlatSurfaces)
    {}

    bool operator==(const FNormalCalculationSettings& Other) const
    {
        return
              ReplaceNormals == Other.ReplaceNormals &&
              ReplaceTangents == Other.ReplaceTangents &&
              HardEdgeAngle == Other.HardEdgeAngle &&
              RepairInvalidNormals == Other.RepairInvalidNormals &&
              ReorthogonalizeTangentSpace == Other.ReorthogonalizeTangentSpace &&
              ScaleByArea == Other.ScaleByArea &&
              ScaleByAngle == Other.ScaleByAngle &&
              SnapNormalsToFlatSurfaces == Other.SnapNormalsToFlatSurfaces;
    }

    bool operator!=(const FNormalCalculationSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FVisibilitySettings
{
    GENERATED_USTRUCT_BODY()

/** If set to true, visibility weights will be used in the reducer. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VisibilitySettings)
    uint8 UseVisibilityWeightsInReducer:1;

/** If set to true, visibility weights will be used when generating new texture coordinates. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VisibilitySettings)
    uint8 UseVisibilityWeightsInTexcoordGenerator:1;

/** Set how aggressively reducer should handle low visibility weights. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VisibilitySettings)
    float VisibilityWeightsPower;

/** If set to true, geometry that is not visible will be removed. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VisibilitySettings)
    uint8 CullOccludedGeometry:1;

/** Set the ForceVisibilityCalculation if true, visibility weights will definitely be computed for the geometry, even if the visibility isn't specifically being used for reduction/materialLOD/culling according to the VisibilitySettings. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VisibilitySettings)
    uint8 ForceVisibilityCalculation:1;

/** Set whether triangles should be regarded visible when viewed from the back. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VisibilitySettings)
    uint8 UseBackfaceCulling:1;

/** The ID of the selection set containing all the scene cameras and scene meshes used when computing visibility. If scene meshes are added, all their vertices will be used as omni-directional cameras. If set to -1, all cameras in the scene will be used. If both selection set name and ID are set, the name will be used. */
    UPROPERTY()
    int32 CameraSelectionSetID;

/** The name of the selection set containing all the scene cameras and scene meshes used when computing visibility. If scene meshes are added, all their vertices will be used as omni-directional cameras. If set to null, all cameras in the scene will be used. If both selection set name and ID are set, the name will be used. */
    UPROPERTY()
    FString CameraSelectionSetName;

/** The ID of the selection set containing all the scene meshes that should occlude the scene when calculating visibility. If set to -1, no occluders will be used. If both selection set name and ID are set, the name will be used. */
    UPROPERTY()
    int32 OccluderSelectionSetID;

/** The name of the selection set containing all the scene meshes used when computing visibility. If set to null, no occluders in the scene will be used. If both selection set name and ID are set, the name will be used. */
    UPROPERTY()
    FString OccluderSelectionSetName;

/** If a group of non-visible triangles (connected to visible triangles) has an area below the FillNonVisibleAreaThreshold - it will receive the same visibility as the neighboring visible triangles. Set to zero to skip filling nonvisible regions. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VisibilitySettings)
    float FillNonVisibleAreaThreshold;

/** If enabled, will remove all the visible triangles that are not occluding any other triangle. It will also remove all non-visible triangles. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VisibilitySettings)
    uint8 RemoveTrianglesNotOccludingOtherTriangles:1;

/** If enabled, will compute the visibility conservatively - meaning that triangles that are visible will be tagged as visible but some non-visible triangles might also be tagged as visible. If this is turned off, then it is no longer guaranteed that all visible triangles are found - but more non-visible triangles will be identified as non-visible. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VisibilitySettings)
    uint8 ConservativeMode:1;

/** Specifies the renderer type when computing visibility. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VisibilitySettings)
    EComputeVisibilityMode ComputeVisibilityMode;

    FVisibilitySettings() :
        UseVisibilityWeightsInReducer(false),
        UseVisibilityWeightsInTexcoordGenerator(false),
        VisibilityWeightsPower(1),
        CullOccludedGeometry(false),
        ForceVisibilityCalculation(false),
        UseBackfaceCulling(true),
        CameraSelectionSetID(-1),
        CameraSelectionSetName(""),
        OccluderSelectionSetID(-1),
        OccluderSelectionSetName(""),
        FillNonVisibleAreaThreshold(0),
        RemoveTrianglesNotOccludingOtherTriangles(false),
        ConservativeMode(false),
        ComputeVisibilityMode(EComputeVisibilityMode::DirectX)
    {
    }

    FVisibilitySettings(const FVisibilitySettings& Other) :
        UseVisibilityWeightsInReducer(Other.UseVisibilityWeightsInReducer),
        UseVisibilityWeightsInTexcoordGenerator(Other.UseVisibilityWeightsInTexcoordGenerator),
        VisibilityWeightsPower(Other.VisibilityWeightsPower),
        CullOccludedGeometry(Other.CullOccludedGeometry),
        ForceVisibilityCalculation(Other.ForceVisibilityCalculation),
        UseBackfaceCulling(Other.UseBackfaceCulling),
        CameraSelectionSetID(Other.CameraSelectionSetID),
        CameraSelectionSetName(Other.CameraSelectionSetName),
        OccluderSelectionSetID(Other.OccluderSelectionSetID),
        OccluderSelectionSetName(Other.OccluderSelectionSetName),
        FillNonVisibleAreaThreshold(Other.FillNonVisibleAreaThreshold),
        RemoveTrianglesNotOccludingOtherTriangles(Other.RemoveTrianglesNotOccludingOtherTriangles),
        ConservativeMode(Other.ConservativeMode),
        ComputeVisibilityMode(Other.ComputeVisibilityMode)
    {}

    bool operator==(const FVisibilitySettings& Other) const
    {
        return
              UseVisibilityWeightsInReducer == Other.UseVisibilityWeightsInReducer &&
              UseVisibilityWeightsInTexcoordGenerator == Other.UseVisibilityWeightsInTexcoordGenerator &&
              VisibilityWeightsPower == Other.VisibilityWeightsPower &&
              CullOccludedGeometry == Other.CullOccludedGeometry &&
              ForceVisibilityCalculation == Other.ForceVisibilityCalculation &&
              UseBackfaceCulling == Other.UseBackfaceCulling &&
              CameraSelectionSetID == Other.CameraSelectionSetID &&
              CameraSelectionSetName == Other.CameraSelectionSetName &&
              OccluderSelectionSetID == Other.OccluderSelectionSetID &&
              OccluderSelectionSetName == Other.OccluderSelectionSetName &&
              FillNonVisibleAreaThreshold == Other.FillNonVisibleAreaThreshold &&
              RemoveTrianglesNotOccludingOtherTriangles == Other.RemoveTrianglesNotOccludingOtherTriangles &&
              ConservativeMode == Other.ConservativeMode &&
              ComputeVisibilityMode == Other.ComputeVisibilityMode;
    }

    bool operator!=(const FVisibilitySettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FBoneSettings
{
    GENERATED_USTRUCT_BODY()

/** Enables or disables the bone reduction processing that actually removes bones. Even with this flag off, the bones per vertex can still be limited. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BoneSettings)
    uint8 UseBoneReducer:1;

/** Enable bone ratio as a reduction target. The reducer will stop when the set bone-ratio has been reached. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BoneSettings)
    uint8 BoneReductionTargetBoneRatioEnabled:1;

/** Decides whether unused bones should be removed. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BoneSettings)
    uint8 RemoveUnusedBones:1;

/** Decides whether unused bones should be removed. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BoneSettings)
    uint8 LimitBonesPerVertex:1;

/** Enable bone count as a reduction target. The reducer will stop when the set bone count has been reached. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BoneSettings)
    uint8 BoneReductionTargetBoneCountEnabled:1;

/** Enable max deviation as a reduction target. The reducer will stop when the set max deviation has been reached. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BoneSettings)
    uint8 BoneReductionTargetMaxDeviationEnabled:1;

/** Decides the maximum limit of how many bones can be connected to each vertex. If for example set to 1, then each vertex will only be linked to 1 bone. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BoneSettings)
    int32 MaxBonePerVertex;

/** Enable on screen size as a reduction target. The reducer will stop when the set on screen size has been reached. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BoneSettings)
    uint8 BoneReductionTargetOnScreenSizeEnabled:1;

/** The stop condition for the bone reducer. Any: the reducer will stop when any single one of the set reduction targets have been reached. All: the reducer will stop when all enabled reduction targets have been set. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BoneSettings)
    EBoneReductionTargetStopCondition BoneReductionTargetStopCondition;

/** The desired bone reduction ratio. The range is 0->1. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BoneSettings)
    float BoneReductionTargetBoneRatio;

/** The desired bone count. The range is 0->inf. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BoneSettings)
    int32 BoneReductionTargetBoneCount;

/** The MaxDeviation value, the maximum surface-deviation between the reduced geometry and the original. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BoneSettings)
    float BoneReductionTargetMaxDeviation;

/** The OnScreenSize value, the maximum surface-deviation between the reduced geometry and the original. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BoneSettings)
    int32 BoneReductionTargetOnScreenSize;

/** The ID of the selection set that contains all of the bones that will be locked, and cannot be removed in the BoneLOD process. If a bone is locked, all its ancestors will be locked also. If the ID is -1, then no bones are selected. */
    UPROPERTY()
    int32 LockBoneSelectionSetID;

/** The name of the selection set that contains all of the bones that will be locked, and cannot be removed in the BoneLOD process. If a bone is locked, all its ancestors will be locked also. If both name and id are set for the locked selection set, the name will be used. */
    UPROPERTY()
    FString LockBoneSelectionSetName;

/** The ID of the selection set that contains all of the bones that will be forced to be removed in the BoneLOD process, UNLESS they are locked. If a bone is set to be removed, all its descendants will be removed also. If both name and id are set for the remove selection set, the name will be used. */
    UPROPERTY()
    int32 RemoveBoneSelectionSetID;

/** The name of the selection set that contains all of the bones that will be forced to be removed in the BoneLOD process, UNLESS they are locked. If a bone is set to be removed, all its descendants will be removed also. If both name and id are set for the remove selection set, the name will be used. */
    UPROPERTY()
    FString RemoveBoneSelectionSetName;

    FBoneSettings() :
        UseBoneReducer(false),
        BoneReductionTargetBoneRatioEnabled(true),
        RemoveUnusedBones(false),
        LimitBonesPerVertex(false),
        BoneReductionTargetBoneCountEnabled(false),
        BoneReductionTargetMaxDeviationEnabled(false),
        MaxBonePerVertex(16),
        BoneReductionTargetOnScreenSizeEnabled(false),
        BoneReductionTargetStopCondition(EBoneReductionTargetStopCondition::All),
        BoneReductionTargetBoneRatio(0.5),
        BoneReductionTargetBoneCount(100),
        BoneReductionTargetMaxDeviation(0),
        BoneReductionTargetOnScreenSize(300),
        LockBoneSelectionSetID(-1),
        LockBoneSelectionSetName(""),
        RemoveBoneSelectionSetID(-1),
        RemoveBoneSelectionSetName("")
    {
    }

    FBoneSettings(const FBoneSettings& Other) :
        UseBoneReducer(Other.UseBoneReducer),
        BoneReductionTargetBoneRatioEnabled(Other.BoneReductionTargetBoneRatioEnabled),
        RemoveUnusedBones(Other.RemoveUnusedBones),
        LimitBonesPerVertex(Other.LimitBonesPerVertex),
        BoneReductionTargetBoneCountEnabled(Other.BoneReductionTargetBoneCountEnabled),
        BoneReductionTargetMaxDeviationEnabled(Other.BoneReductionTargetMaxDeviationEnabled),
        MaxBonePerVertex(Other.MaxBonePerVertex),
        BoneReductionTargetOnScreenSizeEnabled(Other.BoneReductionTargetOnScreenSizeEnabled),
        BoneReductionTargetStopCondition(Other.BoneReductionTargetStopCondition),
        BoneReductionTargetBoneRatio(Other.BoneReductionTargetBoneRatio),
        BoneReductionTargetBoneCount(Other.BoneReductionTargetBoneCount),
        BoneReductionTargetMaxDeviation(Other.BoneReductionTargetMaxDeviation),
        BoneReductionTargetOnScreenSize(Other.BoneReductionTargetOnScreenSize),
        LockBoneSelectionSetID(Other.LockBoneSelectionSetID),
        LockBoneSelectionSetName(Other.LockBoneSelectionSetName),
        RemoveBoneSelectionSetID(Other.RemoveBoneSelectionSetID),
        RemoveBoneSelectionSetName(Other.RemoveBoneSelectionSetName)
    {}

    bool operator==(const FBoneSettings& Other) const
    {
        return
              UseBoneReducer == Other.UseBoneReducer &&
              BoneReductionTargetBoneRatioEnabled == Other.BoneReductionTargetBoneRatioEnabled &&
              RemoveUnusedBones == Other.RemoveUnusedBones &&
              LimitBonesPerVertex == Other.LimitBonesPerVertex &&
              BoneReductionTargetBoneCountEnabled == Other.BoneReductionTargetBoneCountEnabled &&
              BoneReductionTargetMaxDeviationEnabled == Other.BoneReductionTargetMaxDeviationEnabled &&
              MaxBonePerVertex == Other.MaxBonePerVertex &&
              BoneReductionTargetOnScreenSizeEnabled == Other.BoneReductionTargetOnScreenSizeEnabled &&
              BoneReductionTargetStopCondition == Other.BoneReductionTargetStopCondition &&
              BoneReductionTargetBoneRatio == Other.BoneReductionTargetBoneRatio &&
              BoneReductionTargetBoneCount == Other.BoneReductionTargetBoneCount &&
              BoneReductionTargetMaxDeviation == Other.BoneReductionTargetMaxDeviation &&
              BoneReductionTargetOnScreenSize == Other.BoneReductionTargetOnScreenSize &&
              LockBoneSelectionSetID == Other.LockBoneSelectionSetID &&
              LockBoneSelectionSetName == Other.LockBoneSelectionSetName &&
              RemoveBoneSelectionSetID == Other.RemoveBoneSelectionSetID &&
              RemoveBoneSelectionSetName == Other.RemoveBoneSelectionSetName;
    }

    bool operator!=(const FBoneSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FVertexWeightSettings
{
    GENERATED_USTRUCT_BODY()

/** If set, and using the ReductionProcessor or QuadReductionProcessor, the reduction will be weighted based on the weights in the 'VertexWeights' vertex field. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VertexWeightSettings)
    uint8 UseVertexWeightsInReducer:1;

/** If set, and generating new texcoords using either the parameterizeror the chart aggregator, the relative sizes of the output charts will be scaled using the weights in the 'VertexWeights' vertex field. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VertexWeightSettings)
    uint8 UseVertexWeightsInTexcoordGenerator:1;

/** If the name of an existing vertex color field in the input geometry is set here, the existing VertexWeights field will be overwritten by a set created by converting the selected color field according to the other WeightsFromColor settings in this settings object. If both ColorName and the corresponding ColorLevel is set, the processors will prioritize the name. */
    UPROPERTY()
    FString WeightsFromColorName;

/** If the index of an existing vertex color field in the input geometry is set here, the existing VertexWeights field will be overwritten by a set created by converting the selected color field according to the other WeightsFromColor settings in this settings object. If both this and the corresponding ColorName is set, the processors will prioritize the name. */
    UPROPERTY()
    int32 WeightsFromColorLevel;

/** If converting vertex colors to weights, this setting controls which color component is used to create the weights. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VertexWeightSettings)
    EWeightsFromColorComponent WeightsFromColorComponent;

/** If converting vertex colors to weights, this setting controls the max and min resulting vertex weights generated by the input color. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VertexWeightSettings)
    float WeightsFromColorMultiplier;

/** If converting vertex colors to weights, this setting along with WeightsFromColorMultiplier controls how to map the RGBA intensity between 0-1 to weights. Standard mode maps color intensity [0-1] to vertex weight [1/Multiplier - Multiplier]. High mode maps color intensity [0-1] to vertex weight [1 - Multiplier]. Low mode maps color intensity [0-1] to vertex weight [1/Multiplier - 1]. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VertexWeightSettings)
    EWeightsFromColorMode WeightsFromColorMode;

    FVertexWeightSettings() :
        UseVertexWeightsInReducer(false),
        UseVertexWeightsInTexcoordGenerator(false),
        WeightsFromColorName(""),
        WeightsFromColorLevel(-1),
        WeightsFromColorComponent(EWeightsFromColorComponent::Red),
        WeightsFromColorMultiplier(4),
        WeightsFromColorMode(EWeightsFromColorMode::Standard)
    {
    }

    FVertexWeightSettings(const FVertexWeightSettings& Other) :
        UseVertexWeightsInReducer(Other.UseVertexWeightsInReducer),
        UseVertexWeightsInTexcoordGenerator(Other.UseVertexWeightsInTexcoordGenerator),
        WeightsFromColorName(Other.WeightsFromColorName),
        WeightsFromColorLevel(Other.WeightsFromColorLevel),
        WeightsFromColorComponent(Other.WeightsFromColorComponent),
        WeightsFromColorMultiplier(Other.WeightsFromColorMultiplier),
        WeightsFromColorMode(Other.WeightsFromColorMode)
    {}

    bool operator==(const FVertexWeightSettings& Other) const
    {
        return
              UseVertexWeightsInReducer == Other.UseVertexWeightsInReducer &&
              UseVertexWeightsInTexcoordGenerator == Other.UseVertexWeightsInTexcoordGenerator &&
              WeightsFromColorName == Other.WeightsFromColorName &&
              WeightsFromColorLevel == Other.WeightsFromColorLevel &&
              WeightsFromColorComponent == Other.WeightsFromColorComponent &&
              WeightsFromColorMultiplier == Other.WeightsFromColorMultiplier &&
              WeightsFromColorMode == Other.WeightsFromColorMode;
    }

    bool operator!=(const FVertexWeightSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FAttributeTessellationSettings
{
    GENERATED_USTRUCT_BODY()

/** If set to true, attribute tessellation will be calculated on the geometries in the scene. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AttributeTessellationSettings)
    uint8 EnableAttributeTessellation:1;

/** Setting how Simplygon is to calculate or set the tessellation levels for per-triangle regular tessellated attributes. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AttributeTessellationSettings)
    EAttributeTessellationDensityMode AttributeTessellationDensityMode;

/** The transformation space the evaluation should be done in. Valid values are Global and Local. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AttributeTessellationSettings)
    ETransformationSpace TransformationSpace;

/** Setting specific for 'RelativeArea' or 'AbsoluteArea' tessellation density modes. The processor will tessellate a triangle until each value's area is equal or less than the MaxAreaOfTessellatedValue ratio or value, as defined by the mode. Note that the tessellation will still adhere to the MaximumTessellationLevel setting, and not tessellate to a higher level. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AttributeTessellationSettings)
    float MaxAreaOfTessellatedValue;

/** Setting specific for 'RelativeLengthBased' tessellation density mode. The processor will tessellate the values of a triangle until each value's longest edge is equal or less than the MaxLengthOfTessellatedValue ratio value, as defined by the mode. Note that the tessellation will still adhere to the MaximumTessellationLevel setting, and not tessellate to a higher level. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AttributeTessellationSettings)
    float MaxLengthOfTessellatedValue;

/** General tessellation setting. If enabled, only allow a difference of one level between neighbor triangles. This is required by some file formats that store attribute data. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AttributeTessellationSettings)
    uint8 OnlyAllowOneLevelOfDifference:1;

/** General tessellation setting. The minimum level of value tessellation allowed for any one triangle. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AttributeTessellationSettings)
    int32 MinTessellationLevel;

/** General tessellation setting. The maximum level of value tessellation allowed for any one triangle. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AttributeTessellationSettings)
    int32 MaxTessellationLevel;

/** General tessellation setting. The maximum number of values total allowed for one geometry. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AttributeTessellationSettings)
    int32 MaxTotalValuesCount;

    FAttributeTessellationSettings() :
        EnableAttributeTessellation(false),
        AttributeTessellationDensityMode(EAttributeTessellationDensityMode::RelativeArea),
        TransformationSpace(ETransformationSpace::Global),
        MaxAreaOfTessellatedValue(1),
        MaxLengthOfTessellatedValue(1),
        OnlyAllowOneLevelOfDifference(false),
        MinTessellationLevel(0),
        MaxTessellationLevel(5),
        MaxTotalValuesCount(2147483647)
    {
    }

    FAttributeTessellationSettings(const FAttributeTessellationSettings& Other) :
        EnableAttributeTessellation(Other.EnableAttributeTessellation),
        AttributeTessellationDensityMode(Other.AttributeTessellationDensityMode),
        TransformationSpace(Other.TransformationSpace),
        MaxAreaOfTessellatedValue(Other.MaxAreaOfTessellatedValue),
        MaxLengthOfTessellatedValue(Other.MaxLengthOfTessellatedValue),
        OnlyAllowOneLevelOfDifference(Other.OnlyAllowOneLevelOfDifference),
        MinTessellationLevel(Other.MinTessellationLevel),
        MaxTessellationLevel(Other.MaxTessellationLevel),
        MaxTotalValuesCount(Other.MaxTotalValuesCount)
    {}

    bool operator==(const FAttributeTessellationSettings& Other) const
    {
        return
              EnableAttributeTessellation == Other.EnableAttributeTessellation &&
              AttributeTessellationDensityMode == Other.AttributeTessellationDensityMode &&
              TransformationSpace == Other.TransformationSpace &&
              MaxAreaOfTessellatedValue == Other.MaxAreaOfTessellatedValue &&
              MaxLengthOfTessellatedValue == Other.MaxLengthOfTessellatedValue &&
              OnlyAllowOneLevelOfDifference == Other.OnlyAllowOneLevelOfDifference &&
              MinTessellationLevel == Other.MinTessellationLevel &&
              MaxTessellationLevel == Other.MaxTessellationLevel &&
              MaxTotalValuesCount == Other.MaxTotalValuesCount;
    }

    bool operator!=(const FAttributeTessellationSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FInputMaterialSettings
{
    GENERATED_USTRUCT_BODY()

/** The material mapping for the input material this setting object corresponds to, meaning what material of the generated LOD the corresponding input material will be baked into. Both InputMaterialCount and OutputMaterialCount need to be set for this mapping to work, and all original materials need to be mapped to an existing output id. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = InputMaterialSettings)
    int32 MaterialMapping;

    FInputMaterialSettings() :
        MaterialMapping(-1)
    {
    }

    FInputMaterialSettings(const FInputMaterialSettings& Other) :
        MaterialMapping(Other.MaterialMapping)
    {}

    bool operator==(const FInputMaterialSettings& Other) const
    {
        return
              MaterialMapping == Other.MaterialMapping;
    }

    bool operator!=(const FInputMaterialSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FOutputMaterialSettings
{
    GENERATED_USTRUCT_BODY()

/** The width of the texture of the output mapping image. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = OutputMaterialSettings)
    int32 TextureWidth;

/** The height of the texture of the output mapping image. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = OutputMaterialSettings)
    int32 TextureHeight;

/** The multi-sampling level of the output mapping image. Values 1-8 are accepted. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = OutputMaterialSettings)
    int32 MultisamplingLevel;

/** The minimum number of pixels between charts of the output mapping image. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = OutputMaterialSettings)
    int32 GutterSpace;

    FOutputMaterialSettings() :
        TextureWidth(1024),
        TextureHeight(1024),
        MultisamplingLevel(2),
        GutterSpace(4)
    {
    }

    FOutputMaterialSettings(const FOutputMaterialSettings& Other) :
        TextureWidth(Other.TextureWidth),
        TextureHeight(Other.TextureHeight),
        MultisamplingLevel(Other.MultisamplingLevel),
        GutterSpace(Other.GutterSpace)
    {}

    bool operator==(const FOutputMaterialSettings& Other) const
    {
        return
              TextureWidth == Other.TextureWidth &&
              TextureHeight == Other.TextureHeight &&
              MultisamplingLevel == Other.MultisamplingLevel &&
              GutterSpace == Other.GutterSpace;
    }

    bool operator!=(const FOutputMaterialSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FChartAggregatorSettings
{
    GENERATED_USTRUCT_BODY()

/** Determines which method to use when aggregating the UVs. TextureSizeProportions - Aggregated UV charts will be scaled to keep their relative pixel density relative to all other UV charts. The user can still set the size of the output texture maps. SurfaceArea - Aggregated UV charts will have their size set based on its actual geometrical size. OriginalPixelDensity - The combined atlas will be resized to fit each chart so that all charts retain the same amount of pixels as they originally had. This will override any manually set texture size. UVSizeProportions - Aggregated UV charts will have their size set based on its original UV size, disregarding the size of the texture they are used in. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ChartAggregatorSettings)
    EChartAggregatorMode ChartAggregatorMode;

/** If multiple UV charts overlap and have the same material, SurfaceAreaScale specifies which of those instances determines the the output scale. It is only valid when the ChartAggregatorMode is SurfaceArea and SeparateOverlappingCharts is false. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ChartAggregatorSettings)
    ESurfaceAreaScale SurfaceAreaScale;

/** Only used when the TexCoordGeneratorType is ChartAggregator. Set the texture coordinate level to get charts from. If the ChartAggregatorOriginalTexCoordName ha been set, the ChartAggregatorOriginalTexCoordLevel is not used. */
    UPROPERTY()
    int32 OriginalTexCoordLevel;

/** Only used when the TexCoordGeneratorType is ChartAggregator. Set the name of the texture coordinate level to get charts from. If not set, it will use the ChartAggregatorOriginalTexCoordLevel (index) instead. */
    UPROPERTY()
    FString OriginalTexCoordName;

/** Only used when the TexCoordGeneratorType is ChartAggregator. If set, charts that are overlapping in the original texture coords will be separated. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ChartAggregatorSettings)
    uint8 SeparateOverlappingCharts:1;

/** Only used when the TexCoordGeneratorType is ChartAggregator. Set ChartAggregatorKeepOriginalChartProportionsFromChannel to an SG_MATERIAL_CHANNEL_[...]. This channel determines which texture channel to look at when determining which chart proportions to keep. */
    UPROPERTY()
    FString OriginalChartProportionsChannel;

/** Only used when the TexCoordGeneratorType is ChartAggregator. If ChartAggregatorLockUVRotation is enabled, only the original UV rotation will be used. Otherwise 4 rotations are used (90 degree rotations). */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ChartAggregatorSettings)
    uint8 LockUVRotation:1;

    FChartAggregatorSettings() :
        ChartAggregatorMode(EChartAggregatorMode::TextureSizeProportions),
        SurfaceAreaScale(ESurfaceAreaScale::LargestInstance),
        OriginalTexCoordLevel(0),
        OriginalTexCoordName(""),
        SeparateOverlappingCharts(false),
        OriginalChartProportionsChannel("Diffuse"),
        LockUVRotation(false)
    {
    }

    FChartAggregatorSettings(const FChartAggregatorSettings& Other) :
        ChartAggregatorMode(Other.ChartAggregatorMode),
        SurfaceAreaScale(Other.SurfaceAreaScale),
        OriginalTexCoordLevel(Other.OriginalTexCoordLevel),
        OriginalTexCoordName(Other.OriginalTexCoordName),
        SeparateOverlappingCharts(Other.SeparateOverlappingCharts),
        OriginalChartProportionsChannel(Other.OriginalChartProportionsChannel),
        LockUVRotation(Other.LockUVRotation)
    {}

    bool operator==(const FChartAggregatorSettings& Other) const
    {
        return
              ChartAggregatorMode == Other.ChartAggregatorMode &&
              SurfaceAreaScale == Other.SurfaceAreaScale &&
              OriginalTexCoordLevel == Other.OriginalTexCoordLevel &&
              OriginalTexCoordName == Other.OriginalTexCoordName &&
              SeparateOverlappingCharts == Other.SeparateOverlappingCharts &&
              OriginalChartProportionsChannel == Other.OriginalChartProportionsChannel &&
              LockUVRotation == Other.LockUVRotation;
    }

    bool operator!=(const FChartAggregatorSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FParameterizerSettings
{
    GENERATED_USTRUCT_BODY()

/** Only used when the TexCoordGeneratorType is Parameterizer. The maximum allowed texture stretch. Range 0->1. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ParameterizerSettings)
    float MaxStretch;

/** Only used when the TexCoordGeneratorType is Parameterizer. The importance value for trying to have as large and few charts as possible. The closer the value is to 1, the slower it is. Having 0 means no extra focus will be put on reducing the number of charts. Having value 1 means maximum focus will be put on reducing the number of charts and thereby increasing the size of the charts. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ParameterizerSettings)
    float LargeChartsImportance;

    FParameterizerSettings() :
        MaxStretch(0.33),
        LargeChartsImportance(0.2)
    {
    }

    FParameterizerSettings(const FParameterizerSettings& Other) :
        MaxStretch(Other.MaxStretch),
        LargeChartsImportance(Other.LargeChartsImportance)
    {}

    bool operator==(const FParameterizerSettings& Other) const
    {
        return
              MaxStretch == Other.MaxStretch &&
              LargeChartsImportance == Other.LargeChartsImportance;
    }

    bool operator!=(const FParameterizerSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FMappingImageSettings
{
    GENERATED_USTRUCT_BODY()

/** If set, the aggregation processor, reduction processor, or remeshing processor will create a mapping image that maps triangles on the reduced geometry back to triangles on the original geometry. The texture is insert into the MappingImage object. The image data will contain two fields: * RidArray, 'TriangleIds', TupleSize:1, The id of the triangle  * UnsignedShortArray, 'BarycentricCoords', TupleSize:2, Items A & B of the barycentric coordinate on the triangle. The user can control the size of the mapped texture using the values MappingTextureWidth and MappingTextureHeight. */
    UPROPERTY()
    uint8 GenerateMappingImage:1;

/** If true, generates a new texcoords field at the position specified by TexCoordLevel. Will be ignored and always generate texcoords if none are available in the Geometry if GenerateMappingImage is enabled. */
    UPROPERTY()
    uint8 GenerateTexCoords:1;

/** If true, generates a new tangent space fields at position specified by TexCoordLevel, based on the vertex normals and texture coordinates. Tangent space fields will always be created if missing, and GenerateMappingImage is enabled. If GenerateTexCoords is enabled, new tangents will always be generated. */
    UPROPERTY()
    uint8 GenerateTangents:1;

/** The number of input materials used in the original geometry for mapping to multiple output materials. This needs to be set before you can set any specific in-out material mapping. 0 signifies that no in-out material mapping is used, ie. the process will produce one resulting mapping image. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = MappingImageSettings)
    int32 InputMaterialCount;

/** If set, all original texcoord sets are replaced by a single new one which will be used for the mapping image. This means the output scene will be temporarily invalid before the materialtable has been updated to reflect the new changes. This flag has no effect on the remeshing, which always does a full retexturing. */
    UPROPERTY()
    uint8 UseFullRetexturing:1;

/** If true, and also generating one or more mapping images for material casting, the material IDs in the process geometry will be updated to reflect the new, not yet cast output materials. This means the output scene will be temporarily invalid before the materialtable has been updated to reflect the new changes. */
    UPROPERTY()
    uint8 ApplyNewMaterialIds:1;

/** The number of output mapping images that are to be generated. If this is set to more than 1, the material mapping also needs to be set. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = MappingImageSettings)
    int32 OutputMaterialCount;

/** Whether to replace already existing mapping images in the scene. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = MappingImageSettings)
    uint8 ReplaceMappingImages:1;

/** The maximum number of layers in the mapping image. If a remeshed geometry has a lot of transparent triangles, use a higher number to be able to find intersections on the inside of parts of the geometry. This setting only has effect in the remeshing, when running reduction the number of layers is always 1. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = MappingImageSettings)
    int32 MaximumLayers;

/** If true, the remeshing processor will allow mapped transparency in the generated mapping image. This allows material casting where gaps filled by the remeshing processor will be cast as transparent. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = MappingImageSettings)
    uint8 AllowTransparencyMapping:1;

/** The UseAutomaticTextureSize flag. If true, then texture sizes will be computed for the reduced mesh depending on its pixel size on screen. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = MappingImageSettings)
    uint8 UseAutomaticTextureSize:1;

/** Texture dimension length multiplier for the automatic texture size. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = MappingImageSettings)
    float AutomaticTextureSizeMultiplier;

/** If automatic_texture_size is enabled, then force the texture sizes to be a power of 2. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = MappingImageSettings)
    uint8 ForcePower2Texture:1;

/** If enabled, will aggregate all the valid original UVs. If there are invalid original UVs, those parts will receive new parameterized UVs. */
    UPROPERTY()
    uint8 OnlyParameterizeInvalidUVs:1;

/** The texture coordinate level used for mapping image and texture generation. If the TexCoordName has been set, the TexCoordLevel is not used. */
    UPROPERTY()
    int32 TexCoordLevel;

/** The texture coordinate level name used for mapping image and texture generation. If new UVs are created, they will replace the old coordinates in the texture channel with the TexCoordName. If no texture level with this name exists. It will be created. If the TexCoordName is not set, the TexCoordLevel (index) will be used instead. */
    UPROPERTY()
    FString TexCoordName;

/** Determines which method to use when generating the texture coordinates. Parameterizer generate from scratch based on the geometry. ChartAggregator generate based on the original texture coordinates. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = MappingImageSettings)
    ETexCoordGeneratorType TexCoordGeneratorType;

    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = "MappingImageSettings")
    TArray<FInputMaterialSettings> InputMaterialSettings;

    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = "MappingImageSettings")
    TArray<FOutputMaterialSettings> OutputMaterialSettings;

    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = "MappingImageSettings")
    FChartAggregatorSettings ChartAggregatorSettings;

    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = "MappingImageSettings")
    FParameterizerSettings ParameterizerSettings;

    FMappingImageSettings() :
        GenerateMappingImage(false),
        GenerateTexCoords(false),
        GenerateTangents(false),
        InputMaterialCount(0),
        UseFullRetexturing(false),
        ApplyNewMaterialIds(true),
        OutputMaterialCount(1),
        ReplaceMappingImages(true),
        MaximumLayers(3),
        AllowTransparencyMapping(false),
        UseAutomaticTextureSize(false),
        AutomaticTextureSizeMultiplier(1),
        ForcePower2Texture(false),
        OnlyParameterizeInvalidUVs(false),
        TexCoordLevel(0),
        TexCoordName(""),
        TexCoordGeneratorType(ETexCoordGeneratorType::Parameterizer)
    {
        OutputMaterialSettings.Add(FOutputMaterialSettings());
    }

    FMappingImageSettings(const FMappingImageSettings& Other) :
        GenerateMappingImage(Other.GenerateMappingImage),
        GenerateTexCoords(Other.GenerateTexCoords),
        GenerateTangents(Other.GenerateTangents),
        InputMaterialCount(Other.InputMaterialCount),
        UseFullRetexturing(Other.UseFullRetexturing),
        ApplyNewMaterialIds(Other.ApplyNewMaterialIds),
        OutputMaterialCount(Other.OutputMaterialCount),
        ReplaceMappingImages(Other.ReplaceMappingImages),
        MaximumLayers(Other.MaximumLayers),
        AllowTransparencyMapping(Other.AllowTransparencyMapping),
        UseAutomaticTextureSize(Other.UseAutomaticTextureSize),
        AutomaticTextureSizeMultiplier(Other.AutomaticTextureSizeMultiplier),
        ForcePower2Texture(Other.ForcePower2Texture),
        OnlyParameterizeInvalidUVs(Other.OnlyParameterizeInvalidUVs),
        TexCoordLevel(Other.TexCoordLevel),
        TexCoordName(Other.TexCoordName),
        TexCoordGeneratorType(Other.TexCoordGeneratorType)
    {}

    bool operator==(const FMappingImageSettings& Other) const
    {
        return
              GenerateMappingImage == Other.GenerateMappingImage &&
              GenerateTexCoords == Other.GenerateTexCoords &&
              GenerateTangents == Other.GenerateTangents &&
              InputMaterialCount == Other.InputMaterialCount &&
              UseFullRetexturing == Other.UseFullRetexturing &&
              ApplyNewMaterialIds == Other.ApplyNewMaterialIds &&
              OutputMaterialCount == Other.OutputMaterialCount &&
              ReplaceMappingImages == Other.ReplaceMappingImages &&
              MaximumLayers == Other.MaximumLayers &&
              AllowTransparencyMapping == Other.AllowTransparencyMapping &&
              UseAutomaticTextureSize == Other.UseAutomaticTextureSize &&
              AutomaticTextureSizeMultiplier == Other.AutomaticTextureSizeMultiplier &&
              ForcePower2Texture == Other.ForcePower2Texture &&
              OnlyParameterizeInvalidUVs == Other.OnlyParameterizeInvalidUVs &&
              TexCoordLevel == Other.TexCoordLevel &&
              TexCoordName == Other.TexCoordName &&
              TexCoordGeneratorType == Other.TexCoordGeneratorType;
    }

    bool operator!=(const FMappingImageSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FRemeshingSettings
{
    GENERATED_USTRUCT_BODY()

/** Set the topological accuracy of the output mesh. 1=default accuracy, 0=minimal topological accuracy. Lowering the accuracy will lower the memory requirements, and increase remeshing performance, at the cost of lower topological accuracy, where the remesher fills in larger gaps or holes. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RemeshingSettings)
    float TopologicalAccuracy;

/** Set the relative geometrical accuracy of the output mesh. A value less than 1 will lower the accuracy, and lower the output triangle count, but might introduce intersections in the output geometry. A value above 1 will introduce more triangles, and will be able to capture the input geometry more accurately in the output. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RemeshingSettings)
    float GeometricalAccuracy;

/** Z component was a 3-tuple real that acts as the marker designating remeshing processors starting position */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RemeshingSettings)
    float RemeshingModeManualPositionZ;

/** Y component was a 3-tuple real that acts as the marker designating remeshing processors starting position */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RemeshingSettings)
    float RemeshingModeManualPositionY;

/** X component was a 3-tuple real that acts as the marker designating remeshing processors starting position */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RemeshingSettings)
    float RemeshingModeManualPositionX;

/** The on-screen rendering size of the geometry. Allowed values are in the range 20 to 10000 pixels. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RemeshingSettings)
    int32 OnScreenSize;

/** HoleFilling defines how aggressively the remesher will fill holes and cavities. What this does is to measure the volume and hole opening sizes of concavities in the input geometry and fill them in in the remeshing if the concavity is large enough with a small enough opening. This removes a lot of unnecessary geometry and is recommended to be kept at it's default rather than turning it off, it will in the vast majority of cases have a positive effect on the result. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RemeshingSettings)
    EHoleFilling HoleFilling;

/** The remeshing mode, options are Outside, Inside and Manual. RemeshingMode defines if the remeshing processor remeshes the outside or the inside of the input geometry. Manual needs the user to define a position in space that will be considered as outside for the purposes of the remeshing. Position is set with RemeshingModeManualPosition. Hole filling only works with the mode Outside. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RemeshingSettings)
    ERemeshingMode RemeshingMode;

/** The surface transfer mode. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RemeshingSettings)
    ESurfaceTransferMode SurfaceTransferMode;

/** The normal hard angle cutoff in degrees. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RemeshingSettings)
    float HardEdgeAngle;

/** If the flag is set, the normal calculation will only allow hard edges along texture borders. Any vertex normal within a texture chart (not along the border) will be forced soft. Caveat: If this is enabled, some normals might be highly interpolated, and deviate substantially from the triangle normal. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RemeshingSettings)
    uint8 ForceSoftEdgesWithinTextureCharts:1;

/** If set, the vertex normals channel will be sampled from the original mesh. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RemeshingSettings)
    uint8 TransferNormals:1;

/** If set, vertex color channels will be sampled from the original mesh. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RemeshingSettings)
    uint8 TransferColors:1;

/** Selects which SelectionSet should be processed. If set to -1, all geometries in the scene will be processed. */
    UPROPERTY()
    int32 ProcessSelectionSetID;

/** Selects which selection set should be processed. If the selection set is not found, all geometries in the scene will be processed. If both selection set name and ID are set, the name will be used. */
    UPROPERTY()
    FString ProcessSelectionSetName;

/** If false, the processor will remove all geometry and scene nodes which was not selected for processing from the scene. If true, only the geometry in the ProcessSelectionSet will be replaced or updated. If old nodes are kept and a new geometry is added to the scene, it will always be the last child of the scene root. If generating a mappingimage to cast materials, new materialIds will also be appended to the end of the old material table instead of replacing the old ones. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = RemeshingSettings)
    uint8 KeepUnprocessedSceneMeshes:1;

    FRemeshingSettings() :
        TopologicalAccuracy(1),
        GeometricalAccuracy(1),
        RemeshingModeManualPositionZ(0),
        RemeshingModeManualPositionY(0),
        RemeshingModeManualPositionX(0),
        OnScreenSize(300),
        HoleFilling(EHoleFilling::Low),
        RemeshingMode(ERemeshingMode::Outside),
        SurfaceTransferMode(ESurfaceTransferMode::Accurate),
        HardEdgeAngle(75),
        ForceSoftEdgesWithinTextureCharts(false),
        TransferNormals(false),
        TransferColors(false),
        ProcessSelectionSetID(-1),
        ProcessSelectionSetName(""),
        KeepUnprocessedSceneMeshes(false)
    {
    }

    FRemeshingSettings(const FRemeshingSettings& Other) :
        TopologicalAccuracy(Other.TopologicalAccuracy),
        GeometricalAccuracy(Other.GeometricalAccuracy),
        RemeshingModeManualPositionZ(Other.RemeshingModeManualPositionZ),
        RemeshingModeManualPositionY(Other.RemeshingModeManualPositionY),
        RemeshingModeManualPositionX(Other.RemeshingModeManualPositionX),
        OnScreenSize(Other.OnScreenSize),
        HoleFilling(Other.HoleFilling),
        RemeshingMode(Other.RemeshingMode),
        SurfaceTransferMode(Other.SurfaceTransferMode),
        HardEdgeAngle(Other.HardEdgeAngle),
        ForceSoftEdgesWithinTextureCharts(Other.ForceSoftEdgesWithinTextureCharts),
        TransferNormals(Other.TransferNormals),
        TransferColors(Other.TransferColors),
        ProcessSelectionSetID(Other.ProcessSelectionSetID),
        ProcessSelectionSetName(Other.ProcessSelectionSetName),
        KeepUnprocessedSceneMeshes(Other.KeepUnprocessedSceneMeshes)
    {}

    bool operator==(const FRemeshingSettings& Other) const
    {
        return
              TopologicalAccuracy == Other.TopologicalAccuracy &&
              GeometricalAccuracy == Other.GeometricalAccuracy &&
              RemeshingModeManualPositionZ == Other.RemeshingModeManualPositionZ &&
              RemeshingModeManualPositionY == Other.RemeshingModeManualPositionY &&
              RemeshingModeManualPositionX == Other.RemeshingModeManualPositionX &&
              OnScreenSize == Other.OnScreenSize &&
              HoleFilling == Other.HoleFilling &&
              RemeshingMode == Other.RemeshingMode &&
              SurfaceTransferMode == Other.SurfaceTransferMode &&
              HardEdgeAngle == Other.HardEdgeAngle &&
              ForceSoftEdgesWithinTextureCharts == Other.ForceSoftEdgesWithinTextureCharts &&
              TransferNormals == Other.TransferNormals &&
              TransferColors == Other.TransferColors &&
              ProcessSelectionSetID == Other.ProcessSelectionSetID &&
              ProcessSelectionSetName == Other.ProcessSelectionSetName &&
              KeepUnprocessedSceneMeshes == Other.KeepUnprocessedSceneMeshes;
    }

    bool operator!=(const FRemeshingSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FGeometryCullingSettings
{
    GENERATED_USTRUCT_BODY()

/** If true the ScenePlanes in the input scene (or the planes selected by the selection set settings) will be used to clip the mesh. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GeometryCullingSettings)
    uint8 UseClippingPlanes:1;

/** Which SelectionSet containing sceneplanes will be used for clipping. Set name is prioritized over id if both are set. */
    UPROPERTY()
    int32 ClippingPlaneSelectionSetID;

/** Which SelectionSet containing sceneplanes will be used for clipping. Set name is prioritized over id if both are set. */
    UPROPERTY()
    FString ClippingPlaneSelectionSetName;

/** If set, the geometries defined in the matching selection set will be used to clip the process geometry. What side of the geometry that will be culled is determined by the triangle facing, so make sure your winding is correct and that triangles point 'up' toward the space you want to keep. Inconsistent triangle winding or meshes that do not have a clear local inside and outside will cause inconsistent results when used as clipping geometries. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GeometryCullingSettings)
    uint8 UseClippingGeometry:1;

/** Which SelectionSet containing geometries will be used for clipping. Set name is prioritized over id if both are set. */
    UPROPERTY()
    int32 ClippingGeometrySelectionSetID;

/** Which SelectionSet containing geometries will be used for clipping. Set name is prioritized over id if both are set. */
    UPROPERTY()
    FString ClippingGeometrySelectionSetName;

    FGeometryCullingSettings() :
        UseClippingPlanes(false),
        ClippingPlaneSelectionSetID(-1),
        ClippingPlaneSelectionSetName(""),
        UseClippingGeometry(false),
        ClippingGeometrySelectionSetID(-1),
        ClippingGeometrySelectionSetName("")
    {
    }

    FGeometryCullingSettings(const FGeometryCullingSettings& Other) :
        UseClippingPlanes(Other.UseClippingPlanes),
        ClippingPlaneSelectionSetID(Other.ClippingPlaneSelectionSetID),
        ClippingPlaneSelectionSetName(Other.ClippingPlaneSelectionSetName),
        UseClippingGeometry(Other.UseClippingGeometry),
        ClippingGeometrySelectionSetID(Other.ClippingGeometrySelectionSetID),
        ClippingGeometrySelectionSetName(Other.ClippingGeometrySelectionSetName)
    {}

    bool operator==(const FGeometryCullingSettings& Other) const
    {
        return
              UseClippingPlanes == Other.UseClippingPlanes &&
              ClippingPlaneSelectionSetID == Other.ClippingPlaneSelectionSetID &&
              ClippingPlaneSelectionSetName == Other.ClippingPlaneSelectionSetName &&
              UseClippingGeometry == Other.UseClippingGeometry &&
              ClippingGeometrySelectionSetID == Other.ClippingGeometrySelectionSetID &&
              ClippingGeometrySelectionSetName == Other.ClippingGeometrySelectionSetName;
    }

    bool operator!=(const FGeometryCullingSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FAggregationSettings
{
    GENERATED_USTRUCT_BODY()

/** The processor will merge all the geometries in the scene into a single geometry if this is enabled. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AggregationSettings)
    uint8 MergeGeometries:1;

/** Which SelectionSet should be processed. If set to -1, all geometries in the scene will be processed. */
    UPROPERTY()
    int32 ProcessSelectionSetID;

/** Which selection set should be processed. If the selection set is not found, all geometries in the scene will be processed. If both selection set name and ID are set, the name will be used. */
    UPROPERTY()
    FString ProcessSelectionSetName;

/** If false, the processor will remove all geometry and scene meshes which were not selected for processing from the scene. If true, only the geometry in the ProcessSelectionSet will be replaced or updated, while the rest of the scene tree is kept intact. New geometry is always added as the last child of the scene root. If generating a mappingimage to cast materials, new materialIds will also be appended to the end of the old material table instead of replacing the old ones. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AggregationSettings)
    uint8 KeepUnprocessedSceneMeshes:1;

/** Enables culling object insides and permits use of GeometryCullingSettings. If both this and visibility related culling is enabled, this is run first, then visibility. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AggregationSettings)
    uint8 EnableGeometryCulling:1;

/** The accuracy of the triangle intersection math to find and cull insides used by the EnableTriangleCulling setting. Defined from 0 to 1 where 0 is max speed and 1 is max precision. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AggregationSettings)
    float GeometryCullingPrecision;

/** Subdivides the geometry based on the tiling texture coords. The cutting frequency 'SubdivisionTileSize' is a positive integer multiplier (i.e. the mesh will be cut each time its U or V texcoords crosses the SubdivisionTileSize). The output UVs will be in the range [(0,0),(SubdivisionTileSize,SubdivisionTileSize)]. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AggregationSettings)
    uint8 SubdivideGeometryBasedOnUVTiles:1;

/** The cutting frequency used when SubdivideGeometryBasedOnUVTiles is enabled. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AggregationSettings)
    int32 SubdivisionTileSize;

    FAggregationSettings() :
        MergeGeometries(true),
        ProcessSelectionSetID(-1),
        ProcessSelectionSetName(""),
        KeepUnprocessedSceneMeshes(false),
        EnableGeometryCulling(false),
        GeometryCullingPrecision(0.5),
        SubdivideGeometryBasedOnUVTiles(false),
        SubdivisionTileSize(1)
    {
    }

    FAggregationSettings(const FAggregationSettings& Other) :
        MergeGeometries(Other.MergeGeometries),
        ProcessSelectionSetID(Other.ProcessSelectionSetID),
        ProcessSelectionSetName(Other.ProcessSelectionSetName),
        KeepUnprocessedSceneMeshes(Other.KeepUnprocessedSceneMeshes),
        EnableGeometryCulling(Other.EnableGeometryCulling),
        GeometryCullingPrecision(Other.GeometryCullingPrecision),
        SubdivideGeometryBasedOnUVTiles(Other.SubdivideGeometryBasedOnUVTiles),
        SubdivisionTileSize(Other.SubdivisionTileSize)
    {}

    bool operator==(const FAggregationSettings& Other) const
    {
        return
              MergeGeometries == Other.MergeGeometries &&
              ProcessSelectionSetID == Other.ProcessSelectionSetID &&
              ProcessSelectionSetName == Other.ProcessSelectionSetName &&
              KeepUnprocessedSceneMeshes == Other.KeepUnprocessedSceneMeshes &&
              EnableGeometryCulling == Other.EnableGeometryCulling &&
              GeometryCullingPrecision == Other.GeometryCullingPrecision &&
              SubdivideGeometryBasedOnUVTiles == Other.SubdivideGeometryBasedOnUVTiles &&
              SubdivisionTileSize == Other.SubdivisionTileSize;
    }

    bool operator!=(const FAggregationSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FGenerateLightmapTexCoordSettings
{
    GENERATED_USTRUCT_BODY()

/** Property for whether to generate an extra set of TexCoords for LightMapping. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GenerateLightmapTexCoordSettings)
    uint8 GenerateLightmapTexCoord:1;

/** The texture coordinate level used for storing the LightMap UVs. The texcoord name has priority over level. If neither name or level is set then output would be level 0. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GenerateLightmapTexCoordSettings)
    int32 LightmapTexCoordLevel;

/** The texture coordinate level name used for storing the generated Lightmap UVs. If this is not set will default to level. If neither name or level is set then output would be level 0. */
    UPROPERTY()
    FString LightmapTexCoordName;

/** Determines which method to use when aggregating the UVs. TextureSizeProportions - Aggregated UV charts will be scaled to keep their relative pixel density relative to all other UV charts. The user can still set the size of the output texture maps. SurfaceArea - Aggregated UV charts will have their size set based on its actual geometrical size. OriginalPixelDensity - The combined atlas will be resized to fit each chart so that all charts retain the same amount of pixels as they originally had. This will override any manually set texture size. UVSizeProportions - Aggregated UV charts will have their size set based on its original UV size, disregarding the size of the texture they are used in.');. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GenerateLightmapTexCoordSettings)
    EChartAggregatorMode ChartAggregatorMode;

/** The width of the texture of the output mapping image. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GenerateLightmapTexCoordSettings)
    int32 TextureWidth;

/** The height of the texture of the output mapping image. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GenerateLightmapTexCoordSettings)
    int32 TextureHeight;

/** The minimum number of pixels between charts of the output mapping image. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GenerateLightmapTexCoordSettings)
    int32 GutterSpace;

    FGenerateLightmapTexCoordSettings() :
        GenerateLightmapTexCoord(false),
        LightmapTexCoordLevel(1),
        LightmapTexCoordName(""),
        ChartAggregatorMode(EChartAggregatorMode::SurfaceArea),
        TextureWidth(512),
        TextureHeight(512),
        GutterSpace(4)
    {
    }

    FGenerateLightmapTexCoordSettings(const FGenerateLightmapTexCoordSettings& Other) :
        GenerateLightmapTexCoord(Other.GenerateLightmapTexCoord),
        LightmapTexCoordLevel(Other.LightmapTexCoordLevel),
        LightmapTexCoordName(Other.LightmapTexCoordName),
        ChartAggregatorMode(Other.ChartAggregatorMode),
        TextureWidth(Other.TextureWidth),
        TextureHeight(Other.TextureHeight),
        GutterSpace(Other.GutterSpace)
    {}

    bool operator==(const FGenerateLightmapTexCoordSettings& Other) const
    {
        return
              GenerateLightmapTexCoord == Other.GenerateLightmapTexCoord &&
              LightmapTexCoordLevel == Other.LightmapTexCoordLevel &&
              LightmapTexCoordName == Other.LightmapTexCoordName &&
              ChartAggregatorMode == Other.ChartAggregatorMode &&
              TextureWidth == Other.TextureWidth &&
              TextureHeight == Other.TextureHeight &&
              GutterSpace == Other.GutterSpace;
    }

    bool operator!=(const FGenerateLightmapTexCoordSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FFoliageSettings
{
    GENERATED_USTRUCT_BODY()

/** Determines whether to enable separation between foliage and trunk in a vegetation scene. Use the SeparateFoliage[...] settings to determine how parts are separated. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = FoliageSettings)
    uint8 SeparateTrunkAndFoliage:1;

/** Is used to separate the trunk from the foliage in a vegetation scene by comparing each group of connected triangles in the scene with the scene's largest group. If a group's triangle count is below SeparateFoliageTriangleRatio * largestGrouptriangleCount it is treated as foliage and processed into billboards. The trunk is optimized using triangle reduction. The range is 0.0->1.0. 0.0 means nothing will be foliage, 1.0 means everything will be foliage. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = FoliageSettings)
    float SeparateFoliageTriangleRatio;

/** Is used to separate the trunk from the foliage in a vegetation scene by finding each group of connected triangles in the scene and if the triangle count is below SeparateFoliageTriangleThreshold it is treated as foliage and processed into billboards. The trunk is optimized using reduction. The range is 0->large value. 0 means nothing will be foliage, value larger than the maximum triangle count means everything will be foliage. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = FoliageSettings)
    int32 SeparateFoliageTriangleThreshold;

/** Is used to separate the trunk from the foliage in a vegetation scene by finding each group of connected triangles in the scene and if the surface area is below (SeparateFoliageAreaThreshold * AreaOfTheLargestGroupInTheScene) it is treated as foliage and processed into billboards. The trunk is optimized using reduction. The range is 0->large value. 0 means nothing will be foliage, value larger than the maximum surface area means everything will be foliage. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = FoliageSettings)
    float SeparateFoliageAreaThreshold;

/** Is used to separate the trunk from the foliage in a vegetation scene by finding each group of connected triangles in the scene and if the diameter of the group is below (SeparateFoliageSizeThreshold * SceneDiameter) it is treated as foliage and processed into billboards. The trunk is optimized using reduction. The range is 0->large value. 0 means nothing will be foliage, value larger than the scene's diameter means everything will be foliage. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = FoliageSettings)
    float SeparateFoliageSizeThreshold;

/** Determines the triangle reduction ratio for the trunk part that has been separated from the foliage part based on the 'separate foliage' settings. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = FoliageSettings)
    float TrunkReductionRatio;

    FFoliageSettings() :
        SeparateTrunkAndFoliage(false),
        SeparateFoliageTriangleRatio(0.01),
        SeparateFoliageTriangleThreshold(10),
        SeparateFoliageAreaThreshold(0.1),
        SeparateFoliageSizeThreshold(0.1),
        TrunkReductionRatio(0.5)
    {
    }

    FFoliageSettings(const FFoliageSettings& Other) :
        SeparateTrunkAndFoliage(Other.SeparateTrunkAndFoliage),
        SeparateFoliageTriangleRatio(Other.SeparateFoliageTriangleRatio),
        SeparateFoliageTriangleThreshold(Other.SeparateFoliageTriangleThreshold),
        SeparateFoliageAreaThreshold(Other.SeparateFoliageAreaThreshold),
        SeparateFoliageSizeThreshold(Other.SeparateFoliageSizeThreshold),
        TrunkReductionRatio(Other.TrunkReductionRatio)
    {}

    bool operator==(const FFoliageSettings& Other) const
    {
        return
              SeparateTrunkAndFoliage == Other.SeparateTrunkAndFoliage &&
              SeparateFoliageTriangleRatio == Other.SeparateFoliageTriangleRatio &&
              SeparateFoliageTriangleThreshold == Other.SeparateFoliageTriangleThreshold &&
              SeparateFoliageAreaThreshold == Other.SeparateFoliageAreaThreshold &&
              SeparateFoliageSizeThreshold == Other.SeparateFoliageSizeThreshold &&
              TrunkReductionRatio == Other.TrunkReductionRatio;
    }

    bool operator!=(const FFoliageSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FBillboardCloudSettings
{
    GENERATED_USTRUCT_BODY()

/** Specifies how the impostors should be mapped to the scene. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BillboardCloudSettings)
    EBillboardMode BillboardMode;

/** Determines whether to prioritize generating vertical billboards which means they will be optimized to be viewed from the side. Otherwise, if the geometry in the input scene is mostly facing upwards/downwards then the generated billboards will also be facing upwards/downwards which makes them not well suited to being viewed from the side. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BillboardCloudSettings)
    uint8 FavorVerticalPlanes:1;

/** Only applicable if BillboardMode: Foliage. Determines if the scene is intended to be viewed from both sides without back face culling. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BillboardCloudSettings)
    uint8 TwoSided:1;

/** Determines whether to prioritize accurately mapping triangles with higher visibility to billboards. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BillboardCloudSettings)
    uint8 UseVisibilityWeights:1;

/** Determines how many billboards to create. A large BillboardDensity means that more billboards will be created to represent spatially spread out triangles better. Having a low BillboardDensity means that fewer billboards will be created and the distances from original leaves to billboards will get larger. The range is 0->1. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BillboardCloudSettings)
    float BillboardDensity;

/** Determines the maximum amount of planes that are computed for the scene initially. When this criteria is met, it is not guaranteed that all triangles in the scene have been accurately mapped to a billboard. It is not a definite hard limit on the number of billboards because the planes can be split up into multiple planes when they're being cut to match their projections. For instance: if GeometricComplexity is high and there are two completely separated projections on a billboard, then the billboard will be split up into two billboards. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BillboardCloudSettings)
    int32 MaxPlaneCount;

/** Determines the geometric complexity of the billboards. The value range is 0->1, where a value of Zero means that the billboards will be simple and not follow the projection closely. And a value of One means that the geometric complexity will be increased and follow the projection closely. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BillboardCloudSettings)
    float GeometricComplexity;

/** The UpVector used in the Billboard Cloud Processor. Set this if the input scene has an up vector other than Y+. If FavorVerticalPlanes is enabled, the UpVector determines verticality. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = BillboardCloudSettings)
    FVector UpVector;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = BillboardCloudSettings, meta=(EditCondition="BillboardMode==EBillboardMode::Foliage", EditConditionHides))
    FFoliageSettings FoliageSettings;

    FBillboardCloudSettings() :
        BillboardMode(EBillboardMode::OuterShell),
        FavorVerticalPlanes(false),
        TwoSided(true),
        UseVisibilityWeights(true),
        BillboardDensity(0.2),
        MaxPlaneCount(10),
        GeometricComplexity(0.5),
        UpVector(SimplygonIntegrationDefaultUp)
    {
    }

    FBillboardCloudSettings(const FBillboardCloudSettings& Other) :
        BillboardMode(Other.BillboardMode),
        FavorVerticalPlanes(Other.FavorVerticalPlanes),
        TwoSided(Other.TwoSided),
        UseVisibilityWeights(Other.UseVisibilityWeights),
        BillboardDensity(Other.BillboardDensity),
        MaxPlaneCount(Other.MaxPlaneCount),
        GeometricComplexity(Other.GeometricComplexity),
        UpVector(Other.UpVector)
    {}

    bool operator==(const FBillboardCloudSettings& Other) const
    {
        return
              BillboardMode == Other.BillboardMode &&
              FavorVerticalPlanes == Other.FavorVerticalPlanes &&
              TwoSided == Other.TwoSided &&
              UseVisibilityWeights == Other.UseVisibilityWeights &&
              BillboardDensity == Other.BillboardDensity &&
              MaxPlaneCount == Other.MaxPlaneCount &&
              GeometricComplexity == Other.GeometricComplexity &&
              UpVector == Other.UpVector;
    }

    bool operator!=(const FBillboardCloudSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FFlipbookSettings
{
    GENERATED_USTRUCT_BODY()

/** Determines the number of views generated for the flip book impostor. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = FlipbookSettings)
    int32 NumberOfViews;

/** This vector determines the direction of the first view. The rest of the views are uniformly distributed around the scene rotated around the up-vector. The resulting billboard will be oriented in the negative view direction. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = FlipbookSettings)
    FVector ViewDirection;

/** The views are rotated around the up vector and the rendered images are oriented with the up vector. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = FlipbookSettings)
    FVector UpVector;

    FFlipbookSettings() :
        NumberOfViews(9),
        ViewDirection(SimplygonIntegrationDefaultView),
        UpVector(SimplygonIntegrationDefaultUp)
    {
    }

    FFlipbookSettings(const FFlipbookSettings& Other) :
        NumberOfViews(Other.NumberOfViews),
        ViewDirection(Other.ViewDirection),
        UpVector(Other.UpVector)
    {}

    bool operator==(const FFlipbookSettings& Other) const
    {
        return
              NumberOfViews == Other.NumberOfViews &&
              ViewDirection == Other.ViewDirection &&
              UpVector == Other.UpVector;
    }

    bool operator!=(const FFlipbookSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FImpostorFromSingleViewSettings
{
    GENERATED_USTRUCT_BODY()

/** If set, the impostor will exactly conform to the bounds of the geometry. If false, its dimensions will always be diameter*diameter. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ImpostorFromSingleViewSettings)
    uint8 UseTightFitting:1;

/** This determines where the impostor will end up in depth. 0 is 'center', 1 is 'front' and -1 is 'back'. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ImpostorFromSingleViewSettings)
    float TightFittingDepthOffset;

/** If set, the impostor will contain both front and back facing surfaces. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ImpostorFromSingleViewSettings)
    uint8 TwoSided:1;

/** This vector determines how the resulting impostor geometry will be oriented. The billboard will be perpendicular to this vector. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ImpostorFromSingleViewSettings)
    FVector ViewDirection;

/** Normally, the processor will generate an impostor with texcoords from 0.0 to 1.0, giving perfect UV coverage in the final texture. If your engine uses permanent tiling rendering mode, you may need to add a small padding to avoid sub-pixel wrapping artifact at the impostor edges, which this setting supplies. Ex: Setting this to 0.01 will generate texcoords in the range 0.01 to 0.99. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ImpostorFromSingleViewSettings)
    float TexCoordPadding;

    FImpostorFromSingleViewSettings() :
        UseTightFitting(false),
        TightFittingDepthOffset(0),
        TwoSided(false),
        ViewDirection(SimplygonIntegrationDefaultView),
        TexCoordPadding(0)
    {
    }

    FImpostorFromSingleViewSettings(const FImpostorFromSingleViewSettings& Other) :
        UseTightFitting(Other.UseTightFitting),
        TightFittingDepthOffset(Other.TightFittingDepthOffset),
        TwoSided(Other.TwoSided),
        ViewDirection(Other.ViewDirection),
        TexCoordPadding(Other.TexCoordPadding)
    {}

    bool operator==(const FImpostorFromSingleViewSettings& Other) const
    {
        return
              UseTightFitting == Other.UseTightFitting &&
              TightFittingDepthOffset == Other.TightFittingDepthOffset &&
              TwoSided == Other.TwoSided &&
              ViewDirection == Other.ViewDirection &&
              TexCoordPadding == Other.TexCoordPadding;
    }

    bool operator!=(const FImpostorFromSingleViewSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FHighDensityMeshReductionSettings
{
    GENERATED_USTRUCT_BODY()

/** Enable on screen size as a reduction target. The reducer will stop when the set on screen size has been reached. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = HighDensityMeshReductionSettings)
    uint8 OnScreenSizeEnabled:1;

/** The OnScreenSize value, used to calculate the maximum surface-deviation allowed, by assuming errors less than 1 pixel onscreen will not be noticeable. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = HighDensityMeshReductionSettings)
    int32 OnScreenSize;

/** Enable max deviation as a reduction target. The reducer will stop when the set max deviation has been reached. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = HighDensityMeshReductionSettings)
    uint8 MaxDeviationEnabled:1;

/** The MaxDeviation value, the maximum surface-deviation between the reduced geometry and the original. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = HighDensityMeshReductionSettings)
    float MaxDeviation;

/** The stop condition for the reducer to finish processing. Any -> the reducer will stop when any single one of the set reduction targets have been reached. All -> the reducer will stop when all enabled reduction targets have been reached. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = HighDensityMeshReductionSettings)
    EStopCondition StopCondition;

/** The name of the selection set which should be processed. If not set, all geometries in the scene will be processed. */
    UPROPERTY()
    FString ProcessSelectionSetName;

    FHighDensityMeshReductionSettings() :
        OnScreenSizeEnabled(false),
        OnScreenSize(100),
        MaxDeviationEnabled(false),
        MaxDeviation(1),
        StopCondition(EStopCondition::All),
        ProcessSelectionSetName("")
    {
    }

    FHighDensityMeshReductionSettings(const FHighDensityMeshReductionSettings& Other) :
        OnScreenSizeEnabled(Other.OnScreenSizeEnabled),
        OnScreenSize(Other.OnScreenSize),
        MaxDeviationEnabled(Other.MaxDeviationEnabled),
        MaxDeviation(Other.MaxDeviation),
        StopCondition(Other.StopCondition),
        ProcessSelectionSetName(Other.ProcessSelectionSetName)
    {}

    bool operator==(const FHighDensityMeshReductionSettings& Other) const
    {
        return
              OnScreenSizeEnabled == Other.OnScreenSizeEnabled &&
              OnScreenSize == Other.OnScreenSize &&
              MaxDeviationEnabled == Other.MaxDeviationEnabled &&
              MaxDeviation == Other.MaxDeviation &&
              StopCondition == Other.StopCondition &&
              ProcessSelectionSetName == Other.ProcessSelectionSetName;
    }

    bool operator!=(const FHighDensityMeshReductionSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FColorCasterSettings
{
    GENERATED_USTRUCT_BODY()

/** The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ColorCasterSettings)
    FString MaterialChannel;

/** The component in the opacity channel to use as opacity value. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ColorCasterSettings)
    EOpacityChannelComponent OpacityChannelComponent;

/** The type of dithering to use when creating the output object. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ColorCasterSettings)
    EDitherType DitherType;

/** The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ColorCasterSettings)
    EFillMode FillMode;

/** The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ColorCasterSettings)
    FString OpacityChannel;

/** Enable or disable multisampling. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ColorCasterSettings)
    uint8 UseMultisampling:1;

/** If set, the total opacity of the baked layers replaces the alpha value in the output texture. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ColorCasterSettings)
    uint8 BakeOpacityInAlpha:1;

/** File format for output texture. */
    UPROPERTY()
    EOutputImageFileFormat OutputImageFileFormat;

/** DDS compression if output format is DDS. */
    UPROPERTY()
    EOutputDDSCompressionType OutputDDSCompressionType;

/** The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ColorCasterSettings)
    int32 Dilation;

/** The opacity type determines how the opacity channel of this material should be saved. To make (0.0->1.0) map to (transparent-opaque), use 'Opacity'. To make (0.0->1.0) map to (opaque-transparent), use 'Transparency' */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ColorCasterSettings)
    EOutputOpacityType OutputOpacityType;

/** The output pixel format */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ColorCasterSettings)
    EOutputPixelFormat OutputPixelFormat;

/** If this flag is set, the caster will only run if there is at least one input material that has the main input channel which is to be cast. If the flag is not set, the caster will always produce an output, even if it is totally empty/unset. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ColorCasterSettings)
    uint8 SkipCastingIfNoInputChannel:1;

/** If set, output textures are exported in sRGB format. Input texture format is determined by the flag in the corresponding texture node in the material definition. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = ColorCasterSettings)
    uint8 OutputSRGB:1;

    FColorCasterSettings() :
        MaterialChannel(""),
        OpacityChannelComponent(EOpacityChannelComponent::Red),
        DitherType(EDitherType::FloydSteinberg),
        FillMode(EFillMode::Interpolate),
        OpacityChannel("Opacity"),
        UseMultisampling(true),
        BakeOpacityInAlpha(false),
        OutputImageFileFormat(EOutputImageFileFormat::PNG),
        OutputDDSCompressionType(EOutputDDSCompressionType::NoCompression),
        Dilation(10),
        OutputOpacityType(EOutputOpacityType::Opacity),
        OutputPixelFormat(EOutputPixelFormat::R8G8B8A8),
        SkipCastingIfNoInputChannel(false),
        OutputSRGB(true)
    {
    }

    FColorCasterSettings(const FColorCasterSettings& Other) :
        MaterialChannel(Other.MaterialChannel),
        OpacityChannelComponent(Other.OpacityChannelComponent),
        DitherType(Other.DitherType),
        FillMode(Other.FillMode),
        OpacityChannel(Other.OpacityChannel),
        UseMultisampling(Other.UseMultisampling),
        BakeOpacityInAlpha(Other.BakeOpacityInAlpha),
        OutputImageFileFormat(Other.OutputImageFileFormat),
        OutputDDSCompressionType(Other.OutputDDSCompressionType),
        Dilation(Other.Dilation),
        OutputOpacityType(Other.OutputOpacityType),
        OutputPixelFormat(Other.OutputPixelFormat),
        SkipCastingIfNoInputChannel(Other.SkipCastingIfNoInputChannel),
        OutputSRGB(Other.OutputSRGB)
    {}

    bool operator==(const FColorCasterSettings& Other) const
    {
        return
              MaterialChannel == Other.MaterialChannel &&
              OpacityChannelComponent == Other.OpacityChannelComponent &&
              DitherType == Other.DitherType &&
              FillMode == Other.FillMode &&
              OpacityChannel == Other.OpacityChannel &&
              UseMultisampling == Other.UseMultisampling &&
              BakeOpacityInAlpha == Other.BakeOpacityInAlpha &&
              OutputImageFileFormat == Other.OutputImageFileFormat &&
              OutputDDSCompressionType == Other.OutputDDSCompressionType &&
              Dilation == Other.Dilation &&
              OutputOpacityType == Other.OutputOpacityType &&
              OutputPixelFormat == Other.OutputPixelFormat &&
              SkipCastingIfNoInputChannel == Other.SkipCastingIfNoInputChannel &&
              OutputSRGB == Other.OutputSRGB;
    }

    bool operator!=(const FColorCasterSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FOpacityCasterSettings
{
    GENERATED_USTRUCT_BODY()

/** The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = OpacityCasterSettings)
    FString MaterialChannel;

/** The component in the opacity channel to use as opacity value. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = OpacityCasterSettings)
    EOpacityChannelComponent OpacityChannelComponent;

/** The type of dithering to use when creating the output object. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = OpacityCasterSettings)
    EDitherType DitherType;

/** The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = OpacityCasterSettings)
    EFillMode FillMode;

/** The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = OpacityCasterSettings)
    FString OpacityChannel;

/** Enable or disable multisampling. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = OpacityCasterSettings)
    uint8 UseMultisampling:1;

/** If set, output textures are exported in sRGB format. Input texture format is determined by the flag in the corresponding texture node in the material definition. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = OpacityCasterSettings)
    uint8 OutputSRGB:1;

/** File format for output texture. */
    UPROPERTY()
    EOutputImageFileFormat OutputImageFileFormat;

/** DDS compression if output format is DDS. */
    UPROPERTY()
    EOutputDDSCompressionType OutputDDSCompressionType;

/** The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = OpacityCasterSettings)
    int32 Dilation;

/** The opacity type determines how the opacity channel of this material should be saved. To make (0.0->1.0) map to (transparent-opaque), use 'Opacity'. To make (0.0->1.0) map to (opaque-transparent), use 'Transparency' */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = OpacityCasterSettings)
    EOutputOpacityType OutputOpacityType;

/** The output pixel format */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = OpacityCasterSettings)
    EOutputPixelFormat OutputPixelFormat;

/** If set to true, the opacity data will be output directly to tessellated attributes in the scene geometries, rather than to an image. This setting requires that the Scene object is set in the caster. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = OpacityCasterSettings)
    uint8 OutputToTessellatedAttributes:1;

    FOpacityCasterSettings() :
        MaterialChannel(""),
        OpacityChannelComponent(EOpacityChannelComponent::Red),
        DitherType(EDitherType::FloydSteinberg),
        FillMode(EFillMode::Interpolate),
        OpacityChannel("Opacity"),
        UseMultisampling(true),
        OutputSRGB(false),
        OutputImageFileFormat(EOutputImageFileFormat::PNG),
        OutputDDSCompressionType(EOutputDDSCompressionType::NoCompression),
        Dilation(10),
        OutputOpacityType(EOutputOpacityType::Opacity),
        OutputPixelFormat(EOutputPixelFormat::R8G8B8A8),
        OutputToTessellatedAttributes(false)
    {
    }

    FOpacityCasterSettings(const FOpacityCasterSettings& Other) :
        MaterialChannel(Other.MaterialChannel),
        OpacityChannelComponent(Other.OpacityChannelComponent),
        DitherType(Other.DitherType),
        FillMode(Other.FillMode),
        OpacityChannel(Other.OpacityChannel),
        UseMultisampling(Other.UseMultisampling),
        OutputSRGB(Other.OutputSRGB),
        OutputImageFileFormat(Other.OutputImageFileFormat),
        OutputDDSCompressionType(Other.OutputDDSCompressionType),
        Dilation(Other.Dilation),
        OutputOpacityType(Other.OutputOpacityType),
        OutputPixelFormat(Other.OutputPixelFormat),
        OutputToTessellatedAttributes(Other.OutputToTessellatedAttributes)
    {}

    bool operator==(const FOpacityCasterSettings& Other) const
    {
        return
              MaterialChannel == Other.MaterialChannel &&
              OpacityChannelComponent == Other.OpacityChannelComponent &&
              DitherType == Other.DitherType &&
              FillMode == Other.FillMode &&
              OpacityChannel == Other.OpacityChannel &&
              UseMultisampling == Other.UseMultisampling &&
              OutputSRGB == Other.OutputSRGB &&
              OutputImageFileFormat == Other.OutputImageFileFormat &&
              OutputDDSCompressionType == Other.OutputDDSCompressionType &&
              Dilation == Other.Dilation &&
              OutputOpacityType == Other.OutputOpacityType &&
              OutputPixelFormat == Other.OutputPixelFormat &&
              OutputToTessellatedAttributes == Other.OutputToTessellatedAttributes;
    }

    bool operator!=(const FOpacityCasterSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FNormalCasterSettings
{
    GENERATED_USTRUCT_BODY()

/** The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCasterSettings)
    FString MaterialChannel;

/** The component in the opacity channel to use as opacity value. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCasterSettings)
    EOpacityChannelComponent OpacityChannelComponent;

/** The type of dithering to use when creating the output object. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCasterSettings)
    EDitherType DitherType;

/** The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCasterSettings)
    EFillMode FillMode;

/** The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCasterSettings)
    FString OpacityChannel;

/** Enable or disable multisampling. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCasterSettings)
    uint8 UseMultisampling:1;

/** If set, then normals will be flipped if they are back facing, i.e. pointing into the surface. This may introduce artifacts on geometries that have correctly facing normals, so only use for geometries with known back-facing normals. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCasterSettings)
    uint8 FlipBackfacingNormals:1;

/** File format for output texture. */
    UPROPERTY()
    EOutputImageFileFormat OutputImageFileFormat;

/** DDS compression if output format is DDS. */
    UPROPERTY()
    EOutputDDSCompressionType OutputDDSCompressionType;

/** The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCasterSettings)
    int32 Dilation;

/** If set, then the generated normal map will be in tangent space. Please note that the geometry casted to must contain tangent space fields. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCasterSettings)
    uint8 GenerateTangentSpaceNormals:1;

/** The output pixel format */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCasterSettings)
    EOutputPixelFormat OutputPixelFormat;

/** If set, the green channel is assumed to point along the negative bitangent instead of the positive. This is roughly equivalent to switching between left- and righthanded, but some rounding may differ. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCasterSettings)
    uint8 FlipGreen:1;

/** If set, the normal caster calculates the bitangent used for encoding per-fragment using the normal, tangent and bitangent sign instead of interpolating the actual bitangent vertex data. This needs to match the behavior of the renderer to not produce rendering artifacts. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCasterSettings)
    uint8 CalculateBitangentPerFragment:1;

/** If set, the normal caster normalizes the normal and tangent data used for encoding after interpolation. This needs to match the behavior of the renderer to not produce rendering artifacts. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = NormalCasterSettings)
    uint8 NormalizeInterpolatedTangentSpace:1;

    FNormalCasterSettings() :
        MaterialChannel(""),
        OpacityChannelComponent(EOpacityChannelComponent::Red),
        DitherType(EDitherType::FloydSteinberg),
        FillMode(EFillMode::Interpolate),
        OpacityChannel("Opacity"),
        UseMultisampling(true),
        FlipBackfacingNormals(false),
        OutputImageFileFormat(EOutputImageFileFormat::PNG),
        OutputDDSCompressionType(EOutputDDSCompressionType::NoCompression),
        Dilation(10),
        GenerateTangentSpaceNormals(true),
        OutputPixelFormat(EOutputPixelFormat::R8G8B8A8),
        FlipGreen(false),
        CalculateBitangentPerFragment(true),
        NormalizeInterpolatedTangentSpace(false)
    {
    }

    FNormalCasterSettings(const FNormalCasterSettings& Other) :
        MaterialChannel(Other.MaterialChannel),
        OpacityChannelComponent(Other.OpacityChannelComponent),
        DitherType(Other.DitherType),
        FillMode(Other.FillMode),
        OpacityChannel(Other.OpacityChannel),
        UseMultisampling(Other.UseMultisampling),
        FlipBackfacingNormals(Other.FlipBackfacingNormals),
        OutputImageFileFormat(Other.OutputImageFileFormat),
        OutputDDSCompressionType(Other.OutputDDSCompressionType),
        Dilation(Other.Dilation),
        GenerateTangentSpaceNormals(Other.GenerateTangentSpaceNormals),
        OutputPixelFormat(Other.OutputPixelFormat),
        FlipGreen(Other.FlipGreen),
        CalculateBitangentPerFragment(Other.CalculateBitangentPerFragment),
        NormalizeInterpolatedTangentSpace(Other.NormalizeInterpolatedTangentSpace)
    {}

    bool operator==(const FNormalCasterSettings& Other) const
    {
        return
              MaterialChannel == Other.MaterialChannel &&
              OpacityChannelComponent == Other.OpacityChannelComponent &&
              DitherType == Other.DitherType &&
              FillMode == Other.FillMode &&
              OpacityChannel == Other.OpacityChannel &&
              UseMultisampling == Other.UseMultisampling &&
              FlipBackfacingNormals == Other.FlipBackfacingNormals &&
              OutputImageFileFormat == Other.OutputImageFileFormat &&
              OutputDDSCompressionType == Other.OutputDDSCompressionType &&
              Dilation == Other.Dilation &&
              GenerateTangentSpaceNormals == Other.GenerateTangentSpaceNormals &&
              OutputPixelFormat == Other.OutputPixelFormat &&
              FlipGreen == Other.FlipGreen &&
              CalculateBitangentPerFragment == Other.CalculateBitangentPerFragment &&
              NormalizeInterpolatedTangentSpace == Other.NormalizeInterpolatedTangentSpace;
    }

    bool operator!=(const FNormalCasterSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FDisplacementCasterSettings
{
    GENERATED_USTRUCT_BODY()

/** The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = DisplacementCasterSettings)
    FString MaterialChannel;

/** The component in the opacity channel to use as opacity value. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = DisplacementCasterSettings)
    EOpacityChannelComponent OpacityChannelComponent;

/** The type of dithering to use when creating the output object. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = DisplacementCasterSettings)
    EDitherType DitherType;

/** The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = DisplacementCasterSettings)
    EFillMode FillMode;

/** The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = DisplacementCasterSettings)
    FString OpacityChannel;

/** Enable or disable multisampling. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = DisplacementCasterSettings)
    uint8 UseMultisampling:1;

/** All the delta values are divided by this value before storing them into an image. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = DisplacementCasterSettings)
    float DistanceScaling;

/** File format for output texture. */
    UPROPERTY()
    EOutputImageFileFormat OutputImageFileFormat;

/** DDS compression if output format is DDS. */
    UPROPERTY()
    EOutputDDSCompressionType OutputDDSCompressionType;

/** The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = DisplacementCasterSettings)
    int32 Dilation;

/** If set to true, the size of the displacement vector components in the direction of the interpolated normal are stored in the displacement map, instead of the displacement vectors. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = DisplacementCasterSettings)
    uint8 GenerateScalarDisplacement:1;

/** The output pixel format */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = DisplacementCasterSettings)
    EOutputPixelFormat OutputPixelFormat;

/** If set, the displacement vectors are transformed into the destination object tangent space. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = DisplacementCasterSettings)
    uint8 GenerateTangentSpaceDisplacement:1;

/** The texture coordinate level to use for the tangent space displacement vectors. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = DisplacementCasterSettings)
    int32 NormalMapTexCoordLevel;

/** If set to true, the displacement data will be output directly to tessellated attributes in the scene geometries, rather than to an image. This setting requires that the Scene object is set in the caster. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = DisplacementCasterSettings)
    uint8 OutputToTessellatedAttributes:1;

    FDisplacementCasterSettings() :
        MaterialChannel(""),
        OpacityChannelComponent(EOpacityChannelComponent::Red),
        DitherType(EDitherType::FloydSteinberg),
        FillMode(EFillMode::Interpolate),
        OpacityChannel("Opacity"),
        UseMultisampling(true),
        DistanceScaling(1),
        OutputImageFileFormat(EOutputImageFileFormat::PNG),
        OutputDDSCompressionType(EOutputDDSCompressionType::NoCompression),
        Dilation(10),
        GenerateScalarDisplacement(false),
        OutputPixelFormat(EOutputPixelFormat::R8G8B8A8),
        GenerateTangentSpaceDisplacement(true),
        NormalMapTexCoordLevel(-1),
        OutputToTessellatedAttributes(false)
    {
    }

    FDisplacementCasterSettings(const FDisplacementCasterSettings& Other) :
        MaterialChannel(Other.MaterialChannel),
        OpacityChannelComponent(Other.OpacityChannelComponent),
        DitherType(Other.DitherType),
        FillMode(Other.FillMode),
        OpacityChannel(Other.OpacityChannel),
        UseMultisampling(Other.UseMultisampling),
        DistanceScaling(Other.DistanceScaling),
        OutputImageFileFormat(Other.OutputImageFileFormat),
        OutputDDSCompressionType(Other.OutputDDSCompressionType),
        Dilation(Other.Dilation),
        GenerateScalarDisplacement(Other.GenerateScalarDisplacement),
        OutputPixelFormat(Other.OutputPixelFormat),
        GenerateTangentSpaceDisplacement(Other.GenerateTangentSpaceDisplacement),
        NormalMapTexCoordLevel(Other.NormalMapTexCoordLevel),
        OutputToTessellatedAttributes(Other.OutputToTessellatedAttributes)
    {}

    bool operator==(const FDisplacementCasterSettings& Other) const
    {
        return
              MaterialChannel == Other.MaterialChannel &&
              OpacityChannelComponent == Other.OpacityChannelComponent &&
              DitherType == Other.DitherType &&
              FillMode == Other.FillMode &&
              OpacityChannel == Other.OpacityChannel &&
              UseMultisampling == Other.UseMultisampling &&
              DistanceScaling == Other.DistanceScaling &&
              OutputImageFileFormat == Other.OutputImageFileFormat &&
              OutputDDSCompressionType == Other.OutputDDSCompressionType &&
              Dilation == Other.Dilation &&
              GenerateScalarDisplacement == Other.GenerateScalarDisplacement &&
              OutputPixelFormat == Other.OutputPixelFormat &&
              GenerateTangentSpaceDisplacement == Other.GenerateTangentSpaceDisplacement &&
              NormalMapTexCoordLevel == Other.NormalMapTexCoordLevel &&
              OutputToTessellatedAttributes == Other.OutputToTessellatedAttributes;
    }

    bool operator!=(const FDisplacementCasterSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FAmbientOcclusionCasterSettings
{
    GENERATED_USTRUCT_BODY()

/** The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AmbientOcclusionCasterSettings)
    FString MaterialChannel;

/** The component in the opacity channel to use as opacity value. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AmbientOcclusionCasterSettings)
    EOpacityChannelComponent OpacityChannelComponent;

/** The type of dithering to use when creating the output object. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AmbientOcclusionCasterSettings)
    EDitherType DitherType;

/** The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AmbientOcclusionCasterSettings)
    EFillMode FillMode;

/** The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AmbientOcclusionCasterSettings)
    FString OpacityChannel;

/** Enable or disable multisampling. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AmbientOcclusionCasterSettings)
    uint8 UseMultisampling:1;

/** This determines how many rays are traced per pixel (or subpixel) to evaluate the occlusion. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AmbientOcclusionCasterSettings)
    int32 RaysPerPixel;

/** File format for output texture. */
    UPROPERTY()
    EOutputImageFileFormat OutputImageFileFormat;

/** DDS compression if output format is DDS. */
    UPROPERTY()
    EOutputDDSCompressionType OutputDDSCompressionType;

/** The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AmbientOcclusionCasterSettings)
    int32 Dilation;

/** How far away a surface has to be from another surface to generate no occlusion. Only applicable if SimpleOcclusionMode is off. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AmbientOcclusionCasterSettings)
    float OcclusionFalloff;

/** The output pixel format */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AmbientOcclusionCasterSettings)
    EOutputPixelFormat OutputPixelFormat;

/** This is just a basic intensity scaler. Higher is 'darker'. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AmbientOcclusionCasterSettings)
    float OcclusionMultiplier;

/** If set, occlusion will not scale with distance, each ray will only be either fully occluded or not at all. Speeds up processing time. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = AmbientOcclusionCasterSettings)
    uint8 UseSimpleOcclusionMode:1;

    FAmbientOcclusionCasterSettings() :
        MaterialChannel(""),
        OpacityChannelComponent(EOpacityChannelComponent::Red),
        DitherType(EDitherType::FloydSteinberg),
        FillMode(EFillMode::Interpolate),
        OpacityChannel("Opacity"),
        UseMultisampling(true),
        RaysPerPixel(64),
        OutputImageFileFormat(EOutputImageFileFormat::PNG),
        OutputDDSCompressionType(EOutputDDSCompressionType::NoCompression),
        Dilation(10),
        OcclusionFalloff(-1),
        OutputPixelFormat(EOutputPixelFormat::R8G8B8A8),
        OcclusionMultiplier(-1),
        UseSimpleOcclusionMode(false)
    {
    }

    FAmbientOcclusionCasterSettings(const FAmbientOcclusionCasterSettings& Other) :
        MaterialChannel(Other.MaterialChannel),
        OpacityChannelComponent(Other.OpacityChannelComponent),
        DitherType(Other.DitherType),
        FillMode(Other.FillMode),
        OpacityChannel(Other.OpacityChannel),
        UseMultisampling(Other.UseMultisampling),
        RaysPerPixel(Other.RaysPerPixel),
        OutputImageFileFormat(Other.OutputImageFileFormat),
        OutputDDSCompressionType(Other.OutputDDSCompressionType),
        Dilation(Other.Dilation),
        OcclusionFalloff(Other.OcclusionFalloff),
        OutputPixelFormat(Other.OutputPixelFormat),
        OcclusionMultiplier(Other.OcclusionMultiplier),
        UseSimpleOcclusionMode(Other.UseSimpleOcclusionMode)
    {}

    bool operator==(const FAmbientOcclusionCasterSettings& Other) const
    {
        return
              MaterialChannel == Other.MaterialChannel &&
              OpacityChannelComponent == Other.OpacityChannelComponent &&
              DitherType == Other.DitherType &&
              FillMode == Other.FillMode &&
              OpacityChannel == Other.OpacityChannel &&
              UseMultisampling == Other.UseMultisampling &&
              RaysPerPixel == Other.RaysPerPixel &&
              OutputImageFileFormat == Other.OutputImageFileFormat &&
              OutputDDSCompressionType == Other.OutputDDSCompressionType &&
              Dilation == Other.Dilation &&
              OcclusionFalloff == Other.OcclusionFalloff &&
              OutputPixelFormat == Other.OutputPixelFormat &&
              OcclusionMultiplier == Other.OcclusionMultiplier &&
              UseSimpleOcclusionMode == Other.UseSimpleOcclusionMode;
    }

    bool operator!=(const FAmbientOcclusionCasterSettings& Other) const
    {
        return !(*this == Other);
    }

};

USTRUCT(BlueprintType, Blueprintable)
struct FGeometryDataCasterSettings
{
    GENERATED_USTRUCT_BODY()

/** The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast. */
    UPROPERTY()
    FString MaterialChannel;

/** The component in the opacity channel to use as opacity value. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GeometryDataCasterSettings)
    EOpacityChannelComponent OpacityChannelComponent;

/** The type of dithering to use when creating the output object. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GeometryDataCasterSettings)
    EDitherType DitherType;

/** The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GeometryDataCasterSettings)
    EFillMode FillMode;

/** The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GeometryDataCasterSettings)
    FString OpacityChannel;

/** Enable or disable multisampling. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GeometryDataCasterSettings)
    uint8 UseMultisampling:1;

/** The GeometryDataFieldType setting, which specifies what field type to cast in the GeometryDataCaster. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GeometryDataCasterSettings)
    EGeometryDataFieldType GeometryDataFieldType;

/** File format for output texture. */
    UPROPERTY()
    EOutputImageFileFormat OutputImageFileFormat;

/** DDS compression if output format is DDS. */
    UPROPERTY()
    EOutputDDSCompressionType OutputDDSCompressionType;

/** The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GeometryDataCasterSettings)
    int32 Dilation;

/** The GeometryDataFieldIndex setting, which specifies what field index to cast in the GeometryDataCaster, for fields where it is applicable (TexCoords, Tangents, Bitangents and Colors). The setting is ignored for other field types. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GeometryDataCasterSettings)
    int32 GeometryDataFieldIndex;

/** The output pixel format */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GeometryDataCasterSettings)
    EOutputPixelFormat OutputPixelFormat;

/** The MappingLayerIndex setting, which specifies the layer of the mapping image to use for mapping the geometry data. This is useful eg if you have decals which are on layer 0, and the real geometry on layer 1 */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GeometryDataCasterSettings)
    int32 MappingLayerIndex;

/** The inferior/minimum value of field values to map onto the image data range (0->1). The minimum value will be represented by 0 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GeometryDataCasterSettings)
    FVector4 MappingInf;

/** The Superior/maximum value of field values to map onto the image data range (0->1). The maximum value will be represented by 1 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = GeometryDataCasterSettings)
    FVector4 MappingSup;

    FGeometryDataCasterSettings() :
        MaterialChannel(""),
        OpacityChannelComponent(EOpacityChannelComponent::Red),
        DitherType(EDitherType::FloydSteinberg),
        FillMode(EFillMode::Interpolate),
        OpacityChannel("Opacity"),
        UseMultisampling(true),
        GeometryDataFieldType(EGeometryDataFieldType::Coords),
        OutputImageFileFormat(EOutputImageFileFormat::PNG),
        OutputDDSCompressionType(EOutputDDSCompressionType::NoCompression),
        Dilation(10),
        GeometryDataFieldIndex(0),
        OutputPixelFormat(EOutputPixelFormat::R8G8B8A8),
        MappingLayerIndex(0),
        MappingInf(0,0,0,0),
        MappingSup(1,1,1,1)
    {
    }

    FGeometryDataCasterSettings(const FGeometryDataCasterSettings& Other) :
        MaterialChannel(Other.MaterialChannel),
        OpacityChannelComponent(Other.OpacityChannelComponent),
        DitherType(Other.DitherType),
        FillMode(Other.FillMode),
        OpacityChannel(Other.OpacityChannel),
        UseMultisampling(Other.UseMultisampling),
        GeometryDataFieldType(Other.GeometryDataFieldType),
        OutputImageFileFormat(Other.OutputImageFileFormat),
        OutputDDSCompressionType(Other.OutputDDSCompressionType),
        Dilation(Other.Dilation),
        GeometryDataFieldIndex(Other.GeometryDataFieldIndex),
        OutputPixelFormat(Other.OutputPixelFormat),
        MappingLayerIndex(Other.MappingLayerIndex),
        MappingInf(Other.MappingInf),
        MappingSup(Other.MappingSup)
    {}

    bool operator==(const FGeometryDataCasterSettings& Other) const
    {
        return
              MaterialChannel == Other.MaterialChannel &&
              OpacityChannelComponent == Other.OpacityChannelComponent &&
              DitherType == Other.DitherType &&
              FillMode == Other.FillMode &&
              OpacityChannel == Other.OpacityChannel &&
              UseMultisampling == Other.UseMultisampling &&
              GeometryDataFieldType == Other.GeometryDataFieldType &&
              OutputImageFileFormat == Other.OutputImageFileFormat &&
              OutputDDSCompressionType == Other.OutputDDSCompressionType &&
              Dilation == Other.Dilation &&
              GeometryDataFieldIndex == Other.GeometryDataFieldIndex &&
              OutputPixelFormat == Other.OutputPixelFormat &&
              MappingLayerIndex == Other.MappingLayerIndex &&
              MappingInf == Other.MappingInf &&
              MappingSup == Other.MappingSup;
    }

    bool operator!=(const FGeometryDataCasterSettings& Other) const
    {
        return !(*this == Other);
    }

    void UpdateSettings()
    {
        MaterialChannel = ToString(GeometryDataFieldType).Append(FString::FromInt(GeometryDataFieldIndex));
    }
};

USTRUCT(BlueprintType, Blueprintable)
struct FVertexColorCasterSettings
{
    GENERATED_USTRUCT_BODY()

/** The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VertexColorCasterSettings)
    FString MaterialChannel;

/** The component in the opacity channel to use as opacity value. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VertexColorCasterSettings)
    EOpacityChannelComponent OpacityChannelComponent;

/** The type of dithering to use when creating the output object. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VertexColorCasterSettings)
    EDitherType DitherType;

/** The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VertexColorCasterSettings)
    EFillMode FillMode;

/** The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VertexColorCasterSettings)
    FString OpacityChannel;

/** Enable or disable multisampling. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VertexColorCasterSettings)
    uint8 UseMultisampling:1;

/** The OutputColorLevel index. */
    UPROPERTY()
    int32 OutputColorLevel;

/** File format for output texture. */
    UPROPERTY()
    EOutputImageFileFormat OutputImageFileFormat;

/** DDS compression if output format is DDS. */
    UPROPERTY()
    EOutputDDSCompressionType OutputDDSCompressionType;

/** The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VertexColorCasterSettings)
    int32 Dilation;

/** The OutputColorName string . */
    UPROPERTY()
    FString OutputColorName;

/** The output pixel format */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VertexColorCasterSettings)
    EOutputPixelFormat OutputPixelFormat;

/** The color space edge threshold, which will define how many hard color borders there will be. Corners more similar than the threshold will be merged. This works similarly to HardEdgeAngle for normals; lower values leads more hard borders between neighboring corner colors, and higher values will give you more shared, smoother, colors. This also impacts data usage when using packed geometry since (more unique colors) == (more vertices). The distance is measured in RGBA space. */
    UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = VertexColorCasterSettings)
    float ColorSpaceEdgeThreshold;

    FVertexColorCasterSettings() :
        MaterialChannel("BaseColor"),
        OpacityChannelComponent(EOpacityChannelComponent::Red),
        DitherType(EDitherType::FloydSteinberg),
        FillMode(EFillMode::Interpolate),
        OpacityChannel("Opacity"),
        UseMultisampling(true),
        OutputColorLevel(0),
        OutputImageFileFormat(EOutputImageFileFormat::PNG),
        OutputDDSCompressionType(EOutputDDSCompressionType::NoCompression),
        Dilation(10),
        OutputColorName(""),
        OutputPixelFormat(EOutputPixelFormat::R8G8B8A8),
        ColorSpaceEdgeThreshold(2)
    {
    }

    FVertexColorCasterSettings(const FVertexColorCasterSettings& Other) :
        MaterialChannel(Other.MaterialChannel),
        OpacityChannelComponent(Other.OpacityChannelComponent),
        DitherType(Other.DitherType),
        FillMode(Other.FillMode),
        OpacityChannel(Other.OpacityChannel),
        UseMultisampling(Other.UseMultisampling),
        OutputColorLevel(Other.OutputColorLevel),
        OutputImageFileFormat(Other.OutputImageFileFormat),
        OutputDDSCompressionType(Other.OutputDDSCompressionType),
        Dilation(Other.Dilation),
        OutputColorName(Other.OutputColorName),
        OutputPixelFormat(Other.OutputPixelFormat),
        ColorSpaceEdgeThreshold(Other.ColorSpaceEdgeThreshold)
    {}

    bool operator==(const FVertexColorCasterSettings& Other) const
    {
        return
              MaterialChannel == Other.MaterialChannel &&
              OpacityChannelComponent == Other.OpacityChannelComponent &&
              DitherType == Other.DitherType &&
              FillMode == Other.FillMode &&
              OpacityChannel == Other.OpacityChannel &&
              UseMultisampling == Other.UseMultisampling &&
              OutputColorLevel == Other.OutputColorLevel &&
              OutputImageFileFormat == Other.OutputImageFileFormat &&
              OutputDDSCompressionType == Other.OutputDDSCompressionType &&
              Dilation == Other.Dilation &&
              OutputColorName == Other.OutputColorName &&
              OutputPixelFormat == Other.OutputPixelFormat &&
              ColorSpaceEdgeThreshold == Other.ColorSpaceEdgeThreshold;
    }

    bool operator!=(const FVertexColorCasterSettings& Other) const
    {
        return !(*this == Other);
    }

};


USTRUCT(BlueprintType, Blueprintable)
struct SIMPLYGONUOBJECTS_API FReductionPipelineSettings : public FSimplygonPipelineSettings
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Reduction Settings")
    FReductionSettings ReductionSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Repair Settings")
    FRepairSettings RepairSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Normal Calculation Settings")
    FNormalCalculationSettings NormalCalculationSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Visibility Settings")
    FVisibilitySettings VisibilitySettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Bone Settings")
    FBoneSettings BoneSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Vertex Weight Settings")
    FVertexWeightSettings VertexWeightSettings;

    UPROPERTY()
    FAttributeTessellationSettings AttributeTessellationSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mapping Image Settings")
    FMappingImageSettings MappingImageSettings;

    UPROPERTY(EditAnywhere, Instanced, Category = "Material Baking")
    TArray<USimplygonMaterialCaster*> MaterialPropertyCasters;

    FReductionPipelineSettings() :
        ReductionSettings(),
        RepairSettings(),
        NormalCalculationSettings(),
        VisibilitySettings(),
        BoneSettings(),
        VertexWeightSettings(),
        AttributeTessellationSettings(),
        MappingImageSettings()

    {
    }

    ~FReductionPipelineSettings() {}

#if ALLOW_SIMPLYGON
    virtual Simplygon::spPipeline CreatePipeline(Simplygon::ISimplygon* simplygon) override
    {
        Simplygon::spReductionPipeline ReductionPipeline = simplygon->CreateReductionPipeline();

        Simplygon::spReductionSettings PipelineReductionSettings = ReductionPipeline->GetReductionSettings();
        SetReductionSettings(PipelineReductionSettings, ReductionSettings);

        Simplygon::spRepairSettings PipelineRepairSettings = ReductionPipeline->GetRepairSettings();
        SetRepairSettings(PipelineRepairSettings, RepairSettings);

        Simplygon::spNormalCalculationSettings PipelineNormalCalculationSettings = ReductionPipeline->GetNormalCalculationSettings();
        SetNormalCalculationSettings(PipelineNormalCalculationSettings, NormalCalculationSettings);

        Simplygon::spVisibilitySettings PipelineVisibilitySettings = ReductionPipeline->GetVisibilitySettings();
        SetVisibilitySettings(PipelineVisibilitySettings, VisibilitySettings);

        Simplygon::spBoneSettings PipelineBoneSettings = ReductionPipeline->GetBoneSettings();
        SetBoneSettings(PipelineBoneSettings, BoneSettings);

        Simplygon::spVertexWeightSettings PipelineVertexWeightSettings = ReductionPipeline->GetVertexWeightSettings();
        SetVertexWeightSettings(PipelineVertexWeightSettings, VertexWeightSettings);

        Simplygon::spAttributeTessellationSettings PipelineAttributeTessellationSettings = ReductionPipeline->GetAttributeTessellationSettings();
        SetAttributeTessellationSettings(PipelineAttributeTessellationSettings, AttributeTessellationSettings);

        Simplygon::spMappingImageSettings PipelineMappingImageSettings = ReductionPipeline->GetMappingImageSettings();
        UpdateMappingImageSettings();
        SetMappingImageSettings(PipelineMappingImageSettings, MappingImageSettings);

        for (USimplygonMaterialCaster* Caster : MaterialPropertyCasters)
        {
            if(Caster)
            {
                ReductionPipeline->AddMaterialCaster(Caster->CreateMaterialCaster(simplygon), 0);
            }
        }
        return ReductionPipeline;
    }

private:
    void UpdateMappingImageSettings()
    {
       if(MaterialPropertyCasters.Num() > 0)
       {
           MappingImageSettings.GenerateMappingImage = true;
           MappingImageSettings.GenerateTexCoords = true;
           MappingImageSettings.GenerateTangents = true;
           MappingImageSettings.TexCoordLevel = SG_MATERIALBAKING_INDEX;
       }
       else
       {
           FMappingImageSettings DefaultSettings{};
           MappingImageSettings.GenerateMappingImage = DefaultSettings.GenerateMappingImage;
           MappingImageSettings.GenerateTexCoords = DefaultSettings.GenerateTexCoords;
           MappingImageSettings.GenerateTangents = DefaultSettings.GenerateTangents;
       }
    }
    void SetReductionSettings(Simplygon::spReductionSettings InReductionSettings, const FReductionSettings& Settings) const
    {
        InReductionSettings->SetReductionTargetTriangleRatioEnabled(Settings.ReductionTargetTriangleRatioEnabled);
        InReductionSettings->SetReductionTargetTriangleRatio(Settings.ReductionTargetTriangleRatio);
        InReductionSettings->SetReductionTargetTriangleCountEnabled(Settings.ReductionTargetTriangleCountEnabled);
        InReductionSettings->SetReductionTargetTriangleCount(Settings.ReductionTargetTriangleCount);
        InReductionSettings->SetReductionTargetMaxDeviationEnabled(Settings.ReductionTargetMaxDeviationEnabled);
        InReductionSettings->SetReductionTargetMaxDeviation(Settings.ReductionTargetMaxDeviation);
        InReductionSettings->SetReductionTargetOnScreenSizeEnabled(Settings.ReductionTargetOnScreenSizeEnabled);
        InReductionSettings->SetReductionTargetOnScreenSize(Settings.ReductionTargetOnScreenSize);
        InReductionSettings->SetReductionTargetStopCondition((Simplygon::EStopCondition)Settings.ReductionTargetStopCondition);
        InReductionSettings->SetReductionHeuristics((Simplygon::EReductionHeuristics)Settings.ReductionHeuristics);
        InReductionSettings->SetReductionPerformanceMode((Simplygon::EReductionPerformanceMode)Settings.ReductionPerformanceMode);
        InReductionSettings->SetGeometryImportance(Settings.GeometryImportance);
        InReductionSettings->SetMaterialImportance(Settings.MaterialImportance);
        InReductionSettings->SetTextureImportance(Settings.TextureImportance);
        InReductionSettings->SetShadingImportance(Settings.ShadingImportance);
        InReductionSettings->SetGroupImportance(Settings.GroupImportance);
        InReductionSettings->SetVertexColorImportance(Settings.VertexColorImportance);
        InReductionSettings->SetEdgeSetImportance(Settings.EdgeSetImportance);
        InReductionSettings->SetSkinningImportance(Settings.SkinningImportance);
        InReductionSettings->SetCreateGeomorphGeometry(Settings.CreateGeomorphGeometry);
        InReductionSettings->SetAllowDegenerateTexCoords(Settings.AllowDegenerateTexCoords);
        InReductionSettings->SetKeepSymmetry(Settings.KeepSymmetry);
        InReductionSettings->SetUseAutomaticSymmetryDetection(Settings.UseAutomaticSymmetryDetection);
        InReductionSettings->SetUseSymmetryQuadRetriangulator(Settings.UseSymmetryQuadRetriangulator);
        InReductionSettings->SetSymmetryAxis((Simplygon::ESymmetryAxis)Settings.SymmetryAxis);
        InReductionSettings->SetSymmetryOffset(Settings.SymmetryOffset);
        InReductionSettings->SetSymmetryDetectionTolerance(Settings.SymmetryDetectionTolerance);
        InReductionSettings->SetDataCreationPreferences((Simplygon::EDataCreationPreferences)Settings.DataCreationPreferences);
        InReductionSettings->SetGenerateGeomorphData(Settings.GenerateGeomorphData);
        InReductionSettings->SetOutwardMoveMultiplier(Settings.OutwardMoveMultiplier);
        InReductionSettings->SetInwardMoveMultiplier(Settings.InwardMoveMultiplier);
        InReductionSettings->SetMaxEdgeLength(Settings.MaxEdgeLength);
        InReductionSettings->SetUseHighQualityNormalCalculation(Settings.UseHighQualityNormalCalculation);
        InReductionSettings->SetProcessSelectionSetID(Settings.ProcessSelectionSetID);
        InReductionSettings->SetProcessSelectionSetName(TCHAR_TO_ANSI(*Settings.ProcessSelectionSetName));
        InReductionSettings->SetMergeGeometries(Settings.MergeGeometries);
        InReductionSettings->SetKeepUnprocessedSceneMeshes(Settings.KeepUnprocessedSceneMeshes);
        InReductionSettings->SetLockGeometricBorder(Settings.LockGeometricBorder);
        InReductionSettings->SetPreserveQuadFlags(Settings.PreserveQuadFlags);
    }
    void SetRepairSettings(Simplygon::spRepairSettings InRepairSettings, const FRepairSettings& Settings) const
    {
        InRepairSettings->SetUseTJunctionRemover(Settings.UseTJunctionRemover);
        InRepairSettings->SetTJuncDist(Settings.TJuncDist);
        InRepairSettings->SetWeldDist(Settings.WeldDist);
        InRepairSettings->SetWeldOnlyBorderVertices(Settings.WeldOnlyBorderVertices);
        InRepairSettings->SetWeldOnlyWithinMaterial(Settings.WeldOnlyWithinMaterial);
        InRepairSettings->SetWeldOnlyWithinSceneNode(Settings.WeldOnlyWithinSceneNode);
        InRepairSettings->SetWeldOnlyBetweenSceneNodes(Settings.WeldOnlyBetweenSceneNodes);
        InRepairSettings->SetUseWelding(Settings.UseWelding);
        InRepairSettings->SetProgressivePasses(Settings.ProgressivePasses);
    }
    void SetNormalCalculationSettings(Simplygon::spNormalCalculationSettings InNormalCalculationSettings, const FNormalCalculationSettings& Settings) const
    {
        InNormalCalculationSettings->SetReplaceNormals(Settings.ReplaceNormals);
        InNormalCalculationSettings->SetReplaceTangents(Settings.ReplaceTangents);
        InNormalCalculationSettings->SetHardEdgeAngle(Settings.HardEdgeAngle);
        InNormalCalculationSettings->SetRepairInvalidNormals(Settings.RepairInvalidNormals);
        InNormalCalculationSettings->SetReorthogonalizeTangentSpace(Settings.ReorthogonalizeTangentSpace);
        InNormalCalculationSettings->SetScaleByArea(Settings.ScaleByArea);
        InNormalCalculationSettings->SetScaleByAngle(Settings.ScaleByAngle);
        InNormalCalculationSettings->SetSnapNormalsToFlatSurfaces(Settings.SnapNormalsToFlatSurfaces);
    }
    void SetVisibilitySettings(Simplygon::spVisibilitySettings InVisibilitySettings, const FVisibilitySettings& Settings) const
    {
        InVisibilitySettings->SetUseVisibilityWeightsInReducer(Settings.UseVisibilityWeightsInReducer);
        InVisibilitySettings->SetUseVisibilityWeightsInTexcoordGenerator(Settings.UseVisibilityWeightsInTexcoordGenerator);
        InVisibilitySettings->SetVisibilityWeightsPower(Settings.VisibilityWeightsPower);
        InVisibilitySettings->SetCullOccludedGeometry(Settings.CullOccludedGeometry);
        InVisibilitySettings->SetForceVisibilityCalculation(Settings.ForceVisibilityCalculation);
        InVisibilitySettings->SetUseBackfaceCulling(Settings.UseBackfaceCulling);
        InVisibilitySettings->SetCameraSelectionSetID(Settings.CameraSelectionSetID);
        InVisibilitySettings->SetCameraSelectionSetName(TCHAR_TO_ANSI(*Settings.CameraSelectionSetName));
        InVisibilitySettings->SetOccluderSelectionSetID(Settings.OccluderSelectionSetID);
        InVisibilitySettings->SetOccluderSelectionSetName(TCHAR_TO_ANSI(*Settings.OccluderSelectionSetName));
        InVisibilitySettings->SetFillNonVisibleAreaThreshold(Settings.FillNonVisibleAreaThreshold);
        InVisibilitySettings->SetRemoveTrianglesNotOccludingOtherTriangles(Settings.RemoveTrianglesNotOccludingOtherTriangles);
        InVisibilitySettings->SetConservativeMode(Settings.ConservativeMode);
        InVisibilitySettings->SetComputeVisibilityMode((Simplygon::EComputeVisibilityMode)Settings.ComputeVisibilityMode);
    }
    void SetBoneSettings(Simplygon::spBoneSettings InBoneSettings, const FBoneSettings& Settings) const
    {
        InBoneSettings->SetUseBoneReducer(Settings.UseBoneReducer);
        InBoneSettings->SetBoneReductionTargetBoneRatioEnabled(Settings.BoneReductionTargetBoneRatioEnabled);
        InBoneSettings->SetRemoveUnusedBones(Settings.RemoveUnusedBones);
        InBoneSettings->SetLimitBonesPerVertex(Settings.LimitBonesPerVertex);
        InBoneSettings->SetBoneReductionTargetBoneCountEnabled(Settings.BoneReductionTargetBoneCountEnabled);
        InBoneSettings->SetBoneReductionTargetMaxDeviationEnabled(Settings.BoneReductionTargetMaxDeviationEnabled);
        InBoneSettings->SetMaxBonePerVertex(Settings.MaxBonePerVertex);
        InBoneSettings->SetBoneReductionTargetOnScreenSizeEnabled(Settings.BoneReductionTargetOnScreenSizeEnabled);
        InBoneSettings->SetBoneReductionTargetStopCondition((Simplygon::EStopCondition)Settings.BoneReductionTargetStopCondition);
        InBoneSettings->SetBoneReductionTargetBoneRatio(Settings.BoneReductionTargetBoneRatio);
        InBoneSettings->SetBoneReductionTargetBoneCount(Settings.BoneReductionTargetBoneCount);
        InBoneSettings->SetBoneReductionTargetMaxDeviation(Settings.BoneReductionTargetMaxDeviation);
        InBoneSettings->SetBoneReductionTargetOnScreenSize(Settings.BoneReductionTargetOnScreenSize);
        InBoneSettings->SetLockBoneSelectionSetID(Settings.LockBoneSelectionSetID);
        InBoneSettings->SetLockBoneSelectionSetName(TCHAR_TO_ANSI(*Settings.LockBoneSelectionSetName));
        InBoneSettings->SetRemoveBoneSelectionSetID(Settings.RemoveBoneSelectionSetID);
        InBoneSettings->SetRemoveBoneSelectionSetName(TCHAR_TO_ANSI(*Settings.RemoveBoneSelectionSetName));
    }
    void SetVertexWeightSettings(Simplygon::spVertexWeightSettings InVertexWeightSettings, const FVertexWeightSettings& Settings) const
    {
        InVertexWeightSettings->SetUseVertexWeightsInReducer(Settings.UseVertexWeightsInReducer);
        InVertexWeightSettings->SetUseVertexWeightsInTexcoordGenerator(Settings.UseVertexWeightsInTexcoordGenerator);
        InVertexWeightSettings->SetWeightsFromColorName(TCHAR_TO_ANSI(*Settings.WeightsFromColorName));
        InVertexWeightSettings->SetWeightsFromColorLevel(Settings.WeightsFromColorLevel);
        InVertexWeightSettings->SetWeightsFromColorComponent((Simplygon::EColorComponent)Settings.WeightsFromColorComponent);
        InVertexWeightSettings->SetWeightsFromColorMultiplier(Settings.WeightsFromColorMultiplier);
        InVertexWeightSettings->SetWeightsFromColorMode((Simplygon::EWeightsFromColorMode)Settings.WeightsFromColorMode);
    }
    void SetAttributeTessellationSettings(Simplygon::spAttributeTessellationSettings InAttributeTessellationSettings, const FAttributeTessellationSettings& Settings) const
    {
        InAttributeTessellationSettings->SetEnableAttributeTessellation(Settings.EnableAttributeTessellation);
        InAttributeTessellationSettings->SetAttributeTessellationDensityMode((Simplygon::EAttributeTessellationDensityMode)Settings.AttributeTessellationDensityMode);
        InAttributeTessellationSettings->SetTransformationSpace((Simplygon::ETransformationSpace)Settings.TransformationSpace);
        InAttributeTessellationSettings->SetMaxAreaOfTessellatedValue(Settings.MaxAreaOfTessellatedValue);
        InAttributeTessellationSettings->SetMaxLengthOfTessellatedValue(Settings.MaxLengthOfTessellatedValue);
        InAttributeTessellationSettings->SetOnlyAllowOneLevelOfDifference(Settings.OnlyAllowOneLevelOfDifference);
        InAttributeTessellationSettings->SetMinTessellationLevel(Settings.MinTessellationLevel);
        InAttributeTessellationSettings->SetMaxTessellationLevel(Settings.MaxTessellationLevel);
        InAttributeTessellationSettings->SetMaxTotalValuesCount(Settings.MaxTotalValuesCount);
    }
    void SetMappingImageSettings(Simplygon::spMappingImageSettings InMappingImageSettings, const FMappingImageSettings& Settings) const
    {
        InMappingImageSettings->SetGenerateMappingImage(Settings.GenerateMappingImage);
        InMappingImageSettings->SetGenerateTexCoords(Settings.GenerateTexCoords);
        InMappingImageSettings->SetGenerateTangents(Settings.GenerateTangents);
        InMappingImageSettings->SetInputMaterialCount(Settings.InputMaterialCount);
        InMappingImageSettings->SetUseFullRetexturing(Settings.UseFullRetexturing);
        InMappingImageSettings->SetApplyNewMaterialIds(Settings.ApplyNewMaterialIds);
        InMappingImageSettings->SetOutputMaterialCount(Settings.OutputMaterialCount);
        InMappingImageSettings->SetReplaceMappingImages(Settings.ReplaceMappingImages);
        InMappingImageSettings->SetMaximumLayers(Settings.MaximumLayers);
        InMappingImageSettings->SetAllowTransparencyMapping(Settings.AllowTransparencyMapping);
        InMappingImageSettings->SetUseAutomaticTextureSize(Settings.UseAutomaticTextureSize);
        InMappingImageSettings->SetAutomaticTextureSizeMultiplier(Settings.AutomaticTextureSizeMultiplier);
        InMappingImageSettings->SetForcePower2Texture(Settings.ForcePower2Texture);
        InMappingImageSettings->SetOnlyParameterizeInvalidUVs(Settings.OnlyParameterizeInvalidUVs);
        InMappingImageSettings->SetTexCoordLevel(Settings.TexCoordLevel);
        InMappingImageSettings->SetTexCoordName(TCHAR_TO_ANSI(*Settings.TexCoordName));
        InMappingImageSettings->SetTexCoordGeneratorType((Simplygon::ETexcoordGeneratorType)Settings.TexCoordGeneratorType);

        int InputMaterialSettingsIndex = 0;
        InMappingImageSettings->SetInputMaterialCount(Settings.InputMaterialSettings.Num());
        for (FInputMaterialSettings SubSettings : Settings.InputMaterialSettings)
        {
            InMappingImageSettings->GetInputMaterialSettings(InputMaterialSettingsIndex)->SetMaterialMapping(SubSettings.MaterialMapping);
            InputMaterialSettingsIndex++;
        }

        int OutputMaterialSettingsIndex = 0;
        InMappingImageSettings->SetOutputMaterialCount(Settings.OutputMaterialSettings.Num());
        for (FOutputMaterialSettings SubSettings : Settings.OutputMaterialSettings)
        {
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetTextureWidth(SubSettings.TextureWidth);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetTextureHeight(SubSettings.TextureHeight);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetMultisamplingLevel(SubSettings.MultisamplingLevel);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetGutterSpace(SubSettings.GutterSpace);
            OutputMaterialSettingsIndex++;
        }

        InMappingImageSettings->GetChartAggregatorSettings()->SetChartAggregatorMode((Simplygon::EChartAggregatorMode)Settings.ChartAggregatorSettings.ChartAggregatorMode);
        InMappingImageSettings->GetChartAggregatorSettings()->SetSurfaceAreaScale((Simplygon::ESurfaceAreaScale)Settings.ChartAggregatorSettings.SurfaceAreaScale);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalTexCoordLevel(Settings.ChartAggregatorSettings.OriginalTexCoordLevel);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalTexCoordName(TCHAR_TO_ANSI(*Settings.ChartAggregatorSettings.OriginalTexCoordName));
        InMappingImageSettings->GetChartAggregatorSettings()->SetSeparateOverlappingCharts(Settings.ChartAggregatorSettings.SeparateOverlappingCharts);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalChartProportionsChannel(TCHAR_TO_ANSI(*Settings.ChartAggregatorSettings.OriginalChartProportionsChannel));
        InMappingImageSettings->GetChartAggregatorSettings()->SetLockUVRotation(Settings.ChartAggregatorSettings.LockUVRotation);

        InMappingImageSettings->GetParameterizerSettings()->SetMaxStretch(Settings.ParameterizerSettings.MaxStretch);
        InMappingImageSettings->GetParameterizerSettings()->SetLargeChartsImportance(Settings.ParameterizerSettings.LargeChartsImportance);
    }
#endif
};

UCLASS(BlueprintType, Blueprintable)
class SIMPLYGONUOBJECTS_API UReductionPipeline : public USimplygonPipeline
{
    GENERATED_BODY()

public:

    UPROPERTY(EditAnywhere, BlueprintReadWrite,Category = "Settings")
    FReductionPipelineSettings Settings;

    UReductionPipeline()
    {
    }

#if ALLOW_SIMPLYGON
    virtual Simplygon::spPipeline CreatePipeline(Simplygon::ISimplygon* simplygon) override
    {
        return Settings.CreatePipeline(simplygon);
    }

#endif


private:

};


USTRUCT(BlueprintType, Blueprintable)
struct SIMPLYGONUOBJECTS_API FRemeshingPipelineSettings : public FSimplygonPipelineSettings
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Remeshing Settings")
    FRemeshingSettings RemeshingSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Bone Settings")
    FBoneSettings BoneSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Geometry Culling Settings")
    FGeometryCullingSettings GeometryCullingSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Visibility Settings")
    FVisibilitySettings VisibilitySettings;

    UPROPERTY()
    FAttributeTessellationSettings AttributeTessellationSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mapping Image Settings")
    FMappingImageSettings MappingImageSettings;

    UPROPERTY(EditAnywhere, Instanced, Category = "Material Baking")
    TArray<USimplygonMaterialCaster*> MaterialPropertyCasters;

    FRemeshingPipelineSettings() :
        RemeshingSettings(),
        BoneSettings(),
        GeometryCullingSettings(),
        VisibilitySettings(),
        AttributeTessellationSettings(),
        MappingImageSettings()

    {
    }

    ~FRemeshingPipelineSettings() {}

#if ALLOW_SIMPLYGON
    virtual Simplygon::spPipeline CreatePipeline(Simplygon::ISimplygon* simplygon) override
    {
        Simplygon::spRemeshingPipeline RemeshingPipeline = simplygon->CreateRemeshingPipeline();

        Simplygon::spRemeshingSettings PipelineRemeshingSettings = RemeshingPipeline->GetRemeshingSettings();
        SetRemeshingSettings(PipelineRemeshingSettings, RemeshingSettings);

        Simplygon::spBoneSettings PipelineBoneSettings = RemeshingPipeline->GetBoneSettings();
        SetBoneSettings(PipelineBoneSettings, BoneSettings);

        Simplygon::spGeometryCullingSettings PipelineGeometryCullingSettings = RemeshingPipeline->GetGeometryCullingSettings();
        SetGeometryCullingSettings(PipelineGeometryCullingSettings, GeometryCullingSettings);

        Simplygon::spVisibilitySettings PipelineVisibilitySettings = RemeshingPipeline->GetVisibilitySettings();
        SetVisibilitySettings(PipelineVisibilitySettings, VisibilitySettings);

        Simplygon::spAttributeTessellationSettings PipelineAttributeTessellationSettings = RemeshingPipeline->GetAttributeTessellationSettings();
        SetAttributeTessellationSettings(PipelineAttributeTessellationSettings, AttributeTessellationSettings);

        Simplygon::spMappingImageSettings PipelineMappingImageSettings = RemeshingPipeline->GetMappingImageSettings();
        UpdateMappingImageSettings();
        SetMappingImageSettings(PipelineMappingImageSettings, MappingImageSettings);

        for (USimplygonMaterialCaster* Caster : MaterialPropertyCasters)
        {
            if(Caster)
            {
                RemeshingPipeline->AddMaterialCaster(Caster->CreateMaterialCaster(simplygon), 0);
            }
        }
        return RemeshingPipeline;
    }

private:
    void UpdateMappingImageSettings()
    {
       if(MaterialPropertyCasters.Num() > 0)
       {
           MappingImageSettings.GenerateMappingImage = true;
           MappingImageSettings.GenerateTexCoords = true;
           MappingImageSettings.GenerateTangents = true;
           MappingImageSettings.TexCoordLevel = SG_MATERIALBAKING_INDEX;
       }
       else
       {
           FMappingImageSettings DefaultSettings{};
           MappingImageSettings.GenerateMappingImage = DefaultSettings.GenerateMappingImage;
           MappingImageSettings.GenerateTexCoords = DefaultSettings.GenerateTexCoords;
           MappingImageSettings.GenerateTangents = DefaultSettings.GenerateTangents;
       }
    }
    void SetRemeshingSettings(Simplygon::spRemeshingSettings InRemeshingSettings, const FRemeshingSettings& Settings) const
    {
        InRemeshingSettings->SetTopologicalAccuracy(Settings.TopologicalAccuracy);
        InRemeshingSettings->SetGeometricalAccuracy(Settings.GeometricalAccuracy);
        InRemeshingSettings->SetRemeshingModeManualPositionZ(Settings.RemeshingModeManualPositionZ);
        InRemeshingSettings->SetRemeshingModeManualPositionY(Settings.RemeshingModeManualPositionY);
        InRemeshingSettings->SetRemeshingModeManualPositionX(Settings.RemeshingModeManualPositionX);
        InRemeshingSettings->SetOnScreenSize(Settings.OnScreenSize);
        InRemeshingSettings->SetHoleFilling((Simplygon::EHoleFilling)Settings.HoleFilling);
        InRemeshingSettings->SetRemeshingMode((Simplygon::ERemeshingMode)Settings.RemeshingMode);
        InRemeshingSettings->SetSurfaceTransferMode((Simplygon::ESurfaceTransferMode)Settings.SurfaceTransferMode);
        InRemeshingSettings->SetHardEdgeAngle(Settings.HardEdgeAngle);
        InRemeshingSettings->SetForceSoftEdgesWithinTextureCharts(Settings.ForceSoftEdgesWithinTextureCharts);
        InRemeshingSettings->SetTransferNormals(Settings.TransferNormals);
        InRemeshingSettings->SetTransferColors(Settings.TransferColors);
        InRemeshingSettings->SetProcessSelectionSetID(Settings.ProcessSelectionSetID);
        InRemeshingSettings->SetProcessSelectionSetName(TCHAR_TO_ANSI(*Settings.ProcessSelectionSetName));
        InRemeshingSettings->SetKeepUnprocessedSceneMeshes(Settings.KeepUnprocessedSceneMeshes);
    }
    void SetBoneSettings(Simplygon::spBoneSettings InBoneSettings, const FBoneSettings& Settings) const
    {
        InBoneSettings->SetUseBoneReducer(Settings.UseBoneReducer);
        InBoneSettings->SetBoneReductionTargetBoneRatioEnabled(Settings.BoneReductionTargetBoneRatioEnabled);
        InBoneSettings->SetRemoveUnusedBones(Settings.RemoveUnusedBones);
        InBoneSettings->SetLimitBonesPerVertex(Settings.LimitBonesPerVertex);
        InBoneSettings->SetBoneReductionTargetBoneCountEnabled(Settings.BoneReductionTargetBoneCountEnabled);
        InBoneSettings->SetBoneReductionTargetMaxDeviationEnabled(Settings.BoneReductionTargetMaxDeviationEnabled);
        InBoneSettings->SetMaxBonePerVertex(Settings.MaxBonePerVertex);
        InBoneSettings->SetBoneReductionTargetOnScreenSizeEnabled(Settings.BoneReductionTargetOnScreenSizeEnabled);
        InBoneSettings->SetBoneReductionTargetStopCondition((Simplygon::EStopCondition)Settings.BoneReductionTargetStopCondition);
        InBoneSettings->SetBoneReductionTargetBoneRatio(Settings.BoneReductionTargetBoneRatio);
        InBoneSettings->SetBoneReductionTargetBoneCount(Settings.BoneReductionTargetBoneCount);
        InBoneSettings->SetBoneReductionTargetMaxDeviation(Settings.BoneReductionTargetMaxDeviation);
        InBoneSettings->SetBoneReductionTargetOnScreenSize(Settings.BoneReductionTargetOnScreenSize);
        InBoneSettings->SetLockBoneSelectionSetID(Settings.LockBoneSelectionSetID);
        InBoneSettings->SetLockBoneSelectionSetName(TCHAR_TO_ANSI(*Settings.LockBoneSelectionSetName));
        InBoneSettings->SetRemoveBoneSelectionSetID(Settings.RemoveBoneSelectionSetID);
        InBoneSettings->SetRemoveBoneSelectionSetName(TCHAR_TO_ANSI(*Settings.RemoveBoneSelectionSetName));
    }
    void SetGeometryCullingSettings(Simplygon::spGeometryCullingSettings InGeometryCullingSettings, const FGeometryCullingSettings& Settings) const
    {
        InGeometryCullingSettings->SetUseClippingPlanes(Settings.UseClippingPlanes);
        InGeometryCullingSettings->SetClippingPlaneSelectionSetID(Settings.ClippingPlaneSelectionSetID);
        InGeometryCullingSettings->SetClippingPlaneSelectionSetName(TCHAR_TO_ANSI(*Settings.ClippingPlaneSelectionSetName));
        InGeometryCullingSettings->SetUseClippingGeometry(Settings.UseClippingGeometry);
        InGeometryCullingSettings->SetClippingGeometrySelectionSetID(Settings.ClippingGeometrySelectionSetID);
        InGeometryCullingSettings->SetClippingGeometrySelectionSetName(TCHAR_TO_ANSI(*Settings.ClippingGeometrySelectionSetName));
    }
    void SetVisibilitySettings(Simplygon::spVisibilitySettings InVisibilitySettings, const FVisibilitySettings& Settings) const
    {
        InVisibilitySettings->SetUseVisibilityWeightsInReducer(Settings.UseVisibilityWeightsInReducer);
        InVisibilitySettings->SetUseVisibilityWeightsInTexcoordGenerator(Settings.UseVisibilityWeightsInTexcoordGenerator);
        InVisibilitySettings->SetVisibilityWeightsPower(Settings.VisibilityWeightsPower);
        InVisibilitySettings->SetCullOccludedGeometry(Settings.CullOccludedGeometry);
        InVisibilitySettings->SetForceVisibilityCalculation(Settings.ForceVisibilityCalculation);
        InVisibilitySettings->SetUseBackfaceCulling(Settings.UseBackfaceCulling);
        InVisibilitySettings->SetCameraSelectionSetID(Settings.CameraSelectionSetID);
        InVisibilitySettings->SetCameraSelectionSetName(TCHAR_TO_ANSI(*Settings.CameraSelectionSetName));
        InVisibilitySettings->SetOccluderSelectionSetID(Settings.OccluderSelectionSetID);
        InVisibilitySettings->SetOccluderSelectionSetName(TCHAR_TO_ANSI(*Settings.OccluderSelectionSetName));
        InVisibilitySettings->SetFillNonVisibleAreaThreshold(Settings.FillNonVisibleAreaThreshold);
        InVisibilitySettings->SetRemoveTrianglesNotOccludingOtherTriangles(Settings.RemoveTrianglesNotOccludingOtherTriangles);
        InVisibilitySettings->SetConservativeMode(Settings.ConservativeMode);
        InVisibilitySettings->SetComputeVisibilityMode((Simplygon::EComputeVisibilityMode)Settings.ComputeVisibilityMode);
    }
    void SetAttributeTessellationSettings(Simplygon::spAttributeTessellationSettings InAttributeTessellationSettings, const FAttributeTessellationSettings& Settings) const
    {
        InAttributeTessellationSettings->SetEnableAttributeTessellation(Settings.EnableAttributeTessellation);
        InAttributeTessellationSettings->SetAttributeTessellationDensityMode((Simplygon::EAttributeTessellationDensityMode)Settings.AttributeTessellationDensityMode);
        InAttributeTessellationSettings->SetTransformationSpace((Simplygon::ETransformationSpace)Settings.TransformationSpace);
        InAttributeTessellationSettings->SetMaxAreaOfTessellatedValue(Settings.MaxAreaOfTessellatedValue);
        InAttributeTessellationSettings->SetMaxLengthOfTessellatedValue(Settings.MaxLengthOfTessellatedValue);
        InAttributeTessellationSettings->SetOnlyAllowOneLevelOfDifference(Settings.OnlyAllowOneLevelOfDifference);
        InAttributeTessellationSettings->SetMinTessellationLevel(Settings.MinTessellationLevel);
        InAttributeTessellationSettings->SetMaxTessellationLevel(Settings.MaxTessellationLevel);
        InAttributeTessellationSettings->SetMaxTotalValuesCount(Settings.MaxTotalValuesCount);
    }
    void SetMappingImageSettings(Simplygon::spMappingImageSettings InMappingImageSettings, const FMappingImageSettings& Settings) const
    {
        InMappingImageSettings->SetGenerateMappingImage(Settings.GenerateMappingImage);
        InMappingImageSettings->SetGenerateTexCoords(Settings.GenerateTexCoords);
        InMappingImageSettings->SetGenerateTangents(Settings.GenerateTangents);
        InMappingImageSettings->SetInputMaterialCount(Settings.InputMaterialCount);
        InMappingImageSettings->SetUseFullRetexturing(Settings.UseFullRetexturing);
        InMappingImageSettings->SetApplyNewMaterialIds(Settings.ApplyNewMaterialIds);
        InMappingImageSettings->SetOutputMaterialCount(Settings.OutputMaterialCount);
        InMappingImageSettings->SetReplaceMappingImages(Settings.ReplaceMappingImages);
        InMappingImageSettings->SetMaximumLayers(Settings.MaximumLayers);
        InMappingImageSettings->SetAllowTransparencyMapping(Settings.AllowTransparencyMapping);
        InMappingImageSettings->SetUseAutomaticTextureSize(Settings.UseAutomaticTextureSize);
        InMappingImageSettings->SetAutomaticTextureSizeMultiplier(Settings.AutomaticTextureSizeMultiplier);
        InMappingImageSettings->SetForcePower2Texture(Settings.ForcePower2Texture);
        InMappingImageSettings->SetOnlyParameterizeInvalidUVs(Settings.OnlyParameterizeInvalidUVs);
        InMappingImageSettings->SetTexCoordLevel(Settings.TexCoordLevel);
        InMappingImageSettings->SetTexCoordName(TCHAR_TO_ANSI(*Settings.TexCoordName));
        InMappingImageSettings->SetTexCoordGeneratorType((Simplygon::ETexcoordGeneratorType)Settings.TexCoordGeneratorType);

        int InputMaterialSettingsIndex = 0;
        InMappingImageSettings->SetInputMaterialCount(Settings.InputMaterialSettings.Num());
        for (FInputMaterialSettings SubSettings : Settings.InputMaterialSettings)
        {
            InMappingImageSettings->GetInputMaterialSettings(InputMaterialSettingsIndex)->SetMaterialMapping(SubSettings.MaterialMapping);
            InputMaterialSettingsIndex++;
        }

        int OutputMaterialSettingsIndex = 0;
        InMappingImageSettings->SetOutputMaterialCount(Settings.OutputMaterialSettings.Num());
        for (FOutputMaterialSettings SubSettings : Settings.OutputMaterialSettings)
        {
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetTextureWidth(SubSettings.TextureWidth);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetTextureHeight(SubSettings.TextureHeight);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetMultisamplingLevel(SubSettings.MultisamplingLevel);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetGutterSpace(SubSettings.GutterSpace);
            OutputMaterialSettingsIndex++;
        }

        InMappingImageSettings->GetChartAggregatorSettings()->SetChartAggregatorMode((Simplygon::EChartAggregatorMode)Settings.ChartAggregatorSettings.ChartAggregatorMode);
        InMappingImageSettings->GetChartAggregatorSettings()->SetSurfaceAreaScale((Simplygon::ESurfaceAreaScale)Settings.ChartAggregatorSettings.SurfaceAreaScale);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalTexCoordLevel(Settings.ChartAggregatorSettings.OriginalTexCoordLevel);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalTexCoordName(TCHAR_TO_ANSI(*Settings.ChartAggregatorSettings.OriginalTexCoordName));
        InMappingImageSettings->GetChartAggregatorSettings()->SetSeparateOverlappingCharts(Settings.ChartAggregatorSettings.SeparateOverlappingCharts);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalChartProportionsChannel(TCHAR_TO_ANSI(*Settings.ChartAggregatorSettings.OriginalChartProportionsChannel));
        InMappingImageSettings->GetChartAggregatorSettings()->SetLockUVRotation(Settings.ChartAggregatorSettings.LockUVRotation);

        InMappingImageSettings->GetParameterizerSettings()->SetMaxStretch(Settings.ParameterizerSettings.MaxStretch);
        InMappingImageSettings->GetParameterizerSettings()->SetLargeChartsImportance(Settings.ParameterizerSettings.LargeChartsImportance);
    }
#endif
};


USTRUCT(BlueprintType, Blueprintable)
struct SIMPLYGONUOBJECTS_API FAggregationPipelineSettings : public FSimplygonPipelineSettings
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Aggregation Settings")
    FAggregationSettings AggregationSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Visibility Settings")
    FVisibilitySettings VisibilitySettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Geometry Culling Settings")
    FGeometryCullingSettings GeometryCullingSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Vertex Weight Settings")
    FVertexWeightSettings VertexWeightSettings;

    UPROPERTY()
    FAttributeTessellationSettings AttributeTessellationSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mapping Image Settings")
    FMappingImageSettings MappingImageSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Generate Lightmap Tex Coord Settings")
    FGenerateLightmapTexCoordSettings GenerateLightmapTexCoordSettings;

    UPROPERTY(EditAnywhere, Instanced, Category = "Material Baking")
    TArray<USimplygonMaterialCaster*> MaterialPropertyCasters;

    FAggregationPipelineSettings() :
        AggregationSettings(),
        VisibilitySettings(),
        GeometryCullingSettings(),
        VertexWeightSettings(),
        AttributeTessellationSettings(),
        MappingImageSettings(),
        GenerateLightmapTexCoordSettings()

    {
           MappingImageSettings.TexCoordGeneratorType = ETexCoordGeneratorType::ChartAggregator;
    }

    ~FAggregationPipelineSettings() {}

#if ALLOW_SIMPLYGON
    virtual Simplygon::spPipeline CreatePipeline(Simplygon::ISimplygon* simplygon) override
    {
        Simplygon::spAggregationPipeline AggregationPipeline = simplygon->CreateAggregationPipeline();

        Simplygon::spAggregationSettings PipelineAggregationSettings = AggregationPipeline->GetAggregationSettings();
        SetAggregationSettings(PipelineAggregationSettings, AggregationSettings);

        Simplygon::spVisibilitySettings PipelineVisibilitySettings = AggregationPipeline->GetVisibilitySettings();
        SetVisibilitySettings(PipelineVisibilitySettings, VisibilitySettings);

        Simplygon::spGeometryCullingSettings PipelineGeometryCullingSettings = AggregationPipeline->GetGeometryCullingSettings();
        SetGeometryCullingSettings(PipelineGeometryCullingSettings, GeometryCullingSettings);

        Simplygon::spVertexWeightSettings PipelineVertexWeightSettings = AggregationPipeline->GetVertexWeightSettings();
        SetVertexWeightSettings(PipelineVertexWeightSettings, VertexWeightSettings);

        Simplygon::spAttributeTessellationSettings PipelineAttributeTessellationSettings = AggregationPipeline->GetAttributeTessellationSettings();
        SetAttributeTessellationSettings(PipelineAttributeTessellationSettings, AttributeTessellationSettings);

        Simplygon::spMappingImageSettings PipelineMappingImageSettings = AggregationPipeline->GetMappingImageSettings();
        UpdateMappingImageSettings();
        SetMappingImageSettings(PipelineMappingImageSettings, MappingImageSettings);

        Simplygon::spGenerateLightmapTexCoordSettings PipelineGenerateLightmapTexCoordSettings = AggregationPipeline->GetGenerateLightmapTexCoordSettings();
        SetGenerateLightmapTexCoordSettings(PipelineGenerateLightmapTexCoordSettings, GenerateLightmapTexCoordSettings);

        for (USimplygonMaterialCaster* Caster : MaterialPropertyCasters)
        {
            if(Caster)
            {
                AggregationPipeline->AddMaterialCaster(Caster->CreateMaterialCaster(simplygon), 0);
            }
        }
        return AggregationPipeline;
    }

private:
    void UpdateMappingImageSettings()
    {
       if(MaterialPropertyCasters.Num() > 0)
       {
           MappingImageSettings.GenerateMappingImage = true;
           MappingImageSettings.GenerateTexCoords = true;
           MappingImageSettings.GenerateTangents = true;
           MappingImageSettings.TexCoordLevel = SG_MATERIALBAKING_INDEX;
           MappingImageSettings.TexCoordGeneratorType = ETexCoordGeneratorType::ChartAggregator;
       }
       else
       {
           FMappingImageSettings DefaultSettings{};
           MappingImageSettings.GenerateMappingImage = DefaultSettings.GenerateMappingImage;
           MappingImageSettings.GenerateTexCoords = DefaultSettings.GenerateTexCoords;
           MappingImageSettings.GenerateTangents = DefaultSettings.GenerateTangents;
       }
    }
    void SetAggregationSettings(Simplygon::spAggregationSettings InAggregationSettings, const FAggregationSettings& Settings) const
    {
        InAggregationSettings->SetMergeGeometries(Settings.MergeGeometries);
        InAggregationSettings->SetProcessSelectionSetID(Settings.ProcessSelectionSetID);
        InAggregationSettings->SetProcessSelectionSetName(TCHAR_TO_ANSI(*Settings.ProcessSelectionSetName));
        InAggregationSettings->SetKeepUnprocessedSceneMeshes(Settings.KeepUnprocessedSceneMeshes);
        InAggregationSettings->SetEnableGeometryCulling(Settings.EnableGeometryCulling);
        InAggregationSettings->SetGeometryCullingPrecision(Settings.GeometryCullingPrecision);
        InAggregationSettings->SetSubdivideGeometryBasedOnUVTiles(Settings.SubdivideGeometryBasedOnUVTiles);
        InAggregationSettings->SetSubdivisionTileSize(Settings.SubdivisionTileSize);
    }
    void SetVisibilitySettings(Simplygon::spVisibilitySettings InVisibilitySettings, const FVisibilitySettings& Settings) const
    {
        InVisibilitySettings->SetUseVisibilityWeightsInReducer(Settings.UseVisibilityWeightsInReducer);
        InVisibilitySettings->SetUseVisibilityWeightsInTexcoordGenerator(Settings.UseVisibilityWeightsInTexcoordGenerator);
        InVisibilitySettings->SetVisibilityWeightsPower(Settings.VisibilityWeightsPower);
        InVisibilitySettings->SetCullOccludedGeometry(Settings.CullOccludedGeometry);
        InVisibilitySettings->SetForceVisibilityCalculation(Settings.ForceVisibilityCalculation);
        InVisibilitySettings->SetUseBackfaceCulling(Settings.UseBackfaceCulling);
        InVisibilitySettings->SetCameraSelectionSetID(Settings.CameraSelectionSetID);
        InVisibilitySettings->SetCameraSelectionSetName(TCHAR_TO_ANSI(*Settings.CameraSelectionSetName));
        InVisibilitySettings->SetOccluderSelectionSetID(Settings.OccluderSelectionSetID);
        InVisibilitySettings->SetOccluderSelectionSetName(TCHAR_TO_ANSI(*Settings.OccluderSelectionSetName));
        InVisibilitySettings->SetFillNonVisibleAreaThreshold(Settings.FillNonVisibleAreaThreshold);
        InVisibilitySettings->SetRemoveTrianglesNotOccludingOtherTriangles(Settings.RemoveTrianglesNotOccludingOtherTriangles);
        InVisibilitySettings->SetConservativeMode(Settings.ConservativeMode);
        InVisibilitySettings->SetComputeVisibilityMode((Simplygon::EComputeVisibilityMode)Settings.ComputeVisibilityMode);
    }
    void SetGeometryCullingSettings(Simplygon::spGeometryCullingSettings InGeometryCullingSettings, const FGeometryCullingSettings& Settings) const
    {
        InGeometryCullingSettings->SetUseClippingPlanes(Settings.UseClippingPlanes);
        InGeometryCullingSettings->SetClippingPlaneSelectionSetID(Settings.ClippingPlaneSelectionSetID);
        InGeometryCullingSettings->SetClippingPlaneSelectionSetName(TCHAR_TO_ANSI(*Settings.ClippingPlaneSelectionSetName));
        InGeometryCullingSettings->SetUseClippingGeometry(Settings.UseClippingGeometry);
        InGeometryCullingSettings->SetClippingGeometrySelectionSetID(Settings.ClippingGeometrySelectionSetID);
        InGeometryCullingSettings->SetClippingGeometrySelectionSetName(TCHAR_TO_ANSI(*Settings.ClippingGeometrySelectionSetName));
    }
    void SetVertexWeightSettings(Simplygon::spVertexWeightSettings InVertexWeightSettings, const FVertexWeightSettings& Settings) const
    {
        InVertexWeightSettings->SetUseVertexWeightsInReducer(Settings.UseVertexWeightsInReducer);
        InVertexWeightSettings->SetUseVertexWeightsInTexcoordGenerator(Settings.UseVertexWeightsInTexcoordGenerator);
        InVertexWeightSettings->SetWeightsFromColorName(TCHAR_TO_ANSI(*Settings.WeightsFromColorName));
        InVertexWeightSettings->SetWeightsFromColorLevel(Settings.WeightsFromColorLevel);
        InVertexWeightSettings->SetWeightsFromColorComponent((Simplygon::EColorComponent)Settings.WeightsFromColorComponent);
        InVertexWeightSettings->SetWeightsFromColorMultiplier(Settings.WeightsFromColorMultiplier);
        InVertexWeightSettings->SetWeightsFromColorMode((Simplygon::EWeightsFromColorMode)Settings.WeightsFromColorMode);
    }
    void SetAttributeTessellationSettings(Simplygon::spAttributeTessellationSettings InAttributeTessellationSettings, const FAttributeTessellationSettings& Settings) const
    {
        InAttributeTessellationSettings->SetEnableAttributeTessellation(Settings.EnableAttributeTessellation);
        InAttributeTessellationSettings->SetAttributeTessellationDensityMode((Simplygon::EAttributeTessellationDensityMode)Settings.AttributeTessellationDensityMode);
        InAttributeTessellationSettings->SetTransformationSpace((Simplygon::ETransformationSpace)Settings.TransformationSpace);
        InAttributeTessellationSettings->SetMaxAreaOfTessellatedValue(Settings.MaxAreaOfTessellatedValue);
        InAttributeTessellationSettings->SetMaxLengthOfTessellatedValue(Settings.MaxLengthOfTessellatedValue);
        InAttributeTessellationSettings->SetOnlyAllowOneLevelOfDifference(Settings.OnlyAllowOneLevelOfDifference);
        InAttributeTessellationSettings->SetMinTessellationLevel(Settings.MinTessellationLevel);
        InAttributeTessellationSettings->SetMaxTessellationLevel(Settings.MaxTessellationLevel);
        InAttributeTessellationSettings->SetMaxTotalValuesCount(Settings.MaxTotalValuesCount);
    }
    void SetMappingImageSettings(Simplygon::spMappingImageSettings InMappingImageSettings, const FMappingImageSettings& Settings) const
    {
        InMappingImageSettings->SetGenerateMappingImage(Settings.GenerateMappingImage);
        InMappingImageSettings->SetGenerateTexCoords(Settings.GenerateTexCoords);
        InMappingImageSettings->SetGenerateTangents(Settings.GenerateTangents);
        InMappingImageSettings->SetInputMaterialCount(Settings.InputMaterialCount);
        InMappingImageSettings->SetUseFullRetexturing(Settings.UseFullRetexturing);
        InMappingImageSettings->SetApplyNewMaterialIds(Settings.ApplyNewMaterialIds);
        InMappingImageSettings->SetOutputMaterialCount(Settings.OutputMaterialCount);
        InMappingImageSettings->SetReplaceMappingImages(Settings.ReplaceMappingImages);
        InMappingImageSettings->SetMaximumLayers(Settings.MaximumLayers);
        InMappingImageSettings->SetAllowTransparencyMapping(Settings.AllowTransparencyMapping);
        InMappingImageSettings->SetUseAutomaticTextureSize(Settings.UseAutomaticTextureSize);
        InMappingImageSettings->SetAutomaticTextureSizeMultiplier(Settings.AutomaticTextureSizeMultiplier);
        InMappingImageSettings->SetForcePower2Texture(Settings.ForcePower2Texture);
        InMappingImageSettings->SetOnlyParameterizeInvalidUVs(Settings.OnlyParameterizeInvalidUVs);
        InMappingImageSettings->SetTexCoordLevel(Settings.TexCoordLevel);
        InMappingImageSettings->SetTexCoordName(TCHAR_TO_ANSI(*Settings.TexCoordName));
        InMappingImageSettings->SetTexCoordGeneratorType((Simplygon::ETexcoordGeneratorType)Settings.TexCoordGeneratorType);

        int InputMaterialSettingsIndex = 0;
        InMappingImageSettings->SetInputMaterialCount(Settings.InputMaterialSettings.Num());
        for (FInputMaterialSettings SubSettings : Settings.InputMaterialSettings)
        {
            InMappingImageSettings->GetInputMaterialSettings(InputMaterialSettingsIndex)->SetMaterialMapping(SubSettings.MaterialMapping);
            InputMaterialSettingsIndex++;
        }

        int OutputMaterialSettingsIndex = 0;
        InMappingImageSettings->SetOutputMaterialCount(Settings.OutputMaterialSettings.Num());
        for (FOutputMaterialSettings SubSettings : Settings.OutputMaterialSettings)
        {
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetTextureWidth(SubSettings.TextureWidth);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetTextureHeight(SubSettings.TextureHeight);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetMultisamplingLevel(SubSettings.MultisamplingLevel);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetGutterSpace(SubSettings.GutterSpace);
            OutputMaterialSettingsIndex++;
        }

        InMappingImageSettings->GetChartAggregatorSettings()->SetChartAggregatorMode((Simplygon::EChartAggregatorMode)Settings.ChartAggregatorSettings.ChartAggregatorMode);
        InMappingImageSettings->GetChartAggregatorSettings()->SetSurfaceAreaScale((Simplygon::ESurfaceAreaScale)Settings.ChartAggregatorSettings.SurfaceAreaScale);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalTexCoordLevel(Settings.ChartAggregatorSettings.OriginalTexCoordLevel);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalTexCoordName(TCHAR_TO_ANSI(*Settings.ChartAggregatorSettings.OriginalTexCoordName));
        InMappingImageSettings->GetChartAggregatorSettings()->SetSeparateOverlappingCharts(Settings.ChartAggregatorSettings.SeparateOverlappingCharts);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalChartProportionsChannel(TCHAR_TO_ANSI(*Settings.ChartAggregatorSettings.OriginalChartProportionsChannel));
        InMappingImageSettings->GetChartAggregatorSettings()->SetLockUVRotation(Settings.ChartAggregatorSettings.LockUVRotation);

        InMappingImageSettings->GetParameterizerSettings()->SetMaxStretch(Settings.ParameterizerSettings.MaxStretch);
        InMappingImageSettings->GetParameterizerSettings()->SetLargeChartsImportance(Settings.ParameterizerSettings.LargeChartsImportance);
    }
    void SetGenerateLightmapTexCoordSettings(Simplygon::spGenerateLightmapTexCoordSettings InGenerateLightmapTexCoordSettings, const FGenerateLightmapTexCoordSettings& Settings) const
    {
        InGenerateLightmapTexCoordSettings->SetGenerateLightmapTexCoord(Settings.GenerateLightmapTexCoord);
        InGenerateLightmapTexCoordSettings->SetLightmapTexCoordLevel(Settings.LightmapTexCoordLevel);
        InGenerateLightmapTexCoordSettings->SetLightmapTexCoordName(TCHAR_TO_ANSI(*Settings.LightmapTexCoordName));
        InGenerateLightmapTexCoordSettings->SetChartAggregatorMode((Simplygon::EChartAggregatorMode)Settings.ChartAggregatorMode);
        InGenerateLightmapTexCoordSettings->SetTextureWidth(Settings.TextureWidth);
        InGenerateLightmapTexCoordSettings->SetTextureHeight(Settings.TextureHeight);
        InGenerateLightmapTexCoordSettings->SetGutterSpace(Settings.GutterSpace);
    }
#endif
};

UCLASS(BlueprintType, Blueprintable)
class SIMPLYGONUOBJECTS_API UAggregationPipeline : public USimplygonPipeline
{
    GENERATED_BODY()

public:

    UPROPERTY(EditAnywhere, BlueprintReadWrite,Category = "Settings")
    FAggregationPipelineSettings Settings;

    UAggregationPipeline()
    {
    }

#if ALLOW_SIMPLYGON
    virtual Simplygon::spPipeline CreatePipeline(Simplygon::ISimplygon* simplygon) override
    {
        return Settings.CreatePipeline(simplygon);
    }

#endif


private:

};


USTRUCT(BlueprintType, Blueprintable)
struct SIMPLYGONUOBJECTS_API FBillboardCloudPipelineSettings : public FSimplygonPipelineSettings
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Billboard Cloud Settings")
    FBillboardCloudSettings BillboardCloudSettings;

    UPROPERTY()
    FAttributeTessellationSettings AttributeTessellationSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mapping Image Settings")
    FMappingImageSettings MappingImageSettings;

    UPROPERTY(EditAnywhere, Instanced, Category = "Material Baking")
    TArray<USimplygonMaterialCaster*> MaterialPropertyCasters;

    FBillboardCloudPipelineSettings() :
        BillboardCloudSettings(),
        AttributeTessellationSettings(),
        MappingImageSettings()

    {
           BillboardCloudSettings.BillboardMode = EBillboardMode::OuterShell;
    }

    ~FBillboardCloudPipelineSettings() {}

#if ALLOW_SIMPLYGON
    virtual Simplygon::spPipeline CreatePipeline(Simplygon::ISimplygon* simplygon) override
    {
        Simplygon::spBillboardCloudPipeline BillboardCloudPipeline = simplygon->CreateBillboardCloudPipeline();

        Simplygon::spBillboardCloudSettings PipelineBillboardCloudSettings = BillboardCloudPipeline->GetBillboardCloudSettings();
        SetBillboardCloudSettings(PipelineBillboardCloudSettings, BillboardCloudSettings);

        Simplygon::spAttributeTessellationSettings PipelineAttributeTessellationSettings = BillboardCloudPipeline->GetAttributeTessellationSettings();
        SetAttributeTessellationSettings(PipelineAttributeTessellationSettings, AttributeTessellationSettings);

        Simplygon::spMappingImageSettings PipelineMappingImageSettings = BillboardCloudPipeline->GetMappingImageSettings();
        UpdateMappingImageSettings();
        SetMappingImageSettings(PipelineMappingImageSettings, MappingImageSettings);

        for (USimplygonMaterialCaster* Caster : MaterialPropertyCasters)
        {
            if(Caster)
            {
                BillboardCloudPipeline->AddMaterialCaster(Caster->CreateMaterialCaster(simplygon), 0);
            }
        }
        return BillboardCloudPipeline;
    }

private:
    void UpdateMappingImageSettings()
    {
       if(MaterialPropertyCasters.Num() > 0)
       {
           MappingImageSettings.GenerateMappingImage = true;
           MappingImageSettings.GenerateTexCoords = true;
           MappingImageSettings.GenerateTangents = true;
           MappingImageSettings.TexCoordLevel = SG_MATERIALBAKING_INDEX;
       }
       else
       {
           FMappingImageSettings DefaultSettings{};
           MappingImageSettings.GenerateMappingImage = DefaultSettings.GenerateMappingImage;
           MappingImageSettings.GenerateTexCoords = DefaultSettings.GenerateTexCoords;
           MappingImageSettings.GenerateTangents = DefaultSettings.GenerateTangents;
       }
    }
    void SetBillboardCloudSettings(Simplygon::spBillboardCloudSettings InBillboardCloudSettings, const FBillboardCloudSettings& Settings) const
    {
        InBillboardCloudSettings->SetBillboardMode((Simplygon::EBillboardMode)Settings.BillboardMode);
        InBillboardCloudSettings->SetFavorVerticalPlanes(Settings.FavorVerticalPlanes);
        InBillboardCloudSettings->SetTwoSided(Settings.TwoSided);
        InBillboardCloudSettings->SetUseVisibilityWeights(Settings.UseVisibilityWeights);
        InBillboardCloudSettings->SetBillboardDensity(Settings.BillboardDensity);
        InBillboardCloudSettings->SetMaxPlaneCount(Settings.MaxPlaneCount);
        InBillboardCloudSettings->SetGeometricComplexity(Settings.GeometricComplexity);
        InBillboardCloudSettings->SetUpVector((float*)&Settings.UpVector);

        InBillboardCloudSettings->GetFoliageSettings()->SetSeparateTrunkAndFoliage(Settings.FoliageSettings.SeparateTrunkAndFoliage);
        InBillboardCloudSettings->GetFoliageSettings()->SetSeparateFoliageTriangleRatio(Settings.FoliageSettings.SeparateFoliageTriangleRatio);
        InBillboardCloudSettings->GetFoliageSettings()->SetSeparateFoliageTriangleThreshold(Settings.FoliageSettings.SeparateFoliageTriangleThreshold);
        InBillboardCloudSettings->GetFoliageSettings()->SetSeparateFoliageAreaThreshold(Settings.FoliageSettings.SeparateFoliageAreaThreshold);
        InBillboardCloudSettings->GetFoliageSettings()->SetSeparateFoliageSizeThreshold(Settings.FoliageSettings.SeparateFoliageSizeThreshold);
        InBillboardCloudSettings->GetFoliageSettings()->SetTrunkReductionRatio(Settings.FoliageSettings.TrunkReductionRatio);
    }
    void SetAttributeTessellationSettings(Simplygon::spAttributeTessellationSettings InAttributeTessellationSettings, const FAttributeTessellationSettings& Settings) const
    {
        InAttributeTessellationSettings->SetEnableAttributeTessellation(Settings.EnableAttributeTessellation);
        InAttributeTessellationSettings->SetAttributeTessellationDensityMode((Simplygon::EAttributeTessellationDensityMode)Settings.AttributeTessellationDensityMode);
        InAttributeTessellationSettings->SetTransformationSpace((Simplygon::ETransformationSpace)Settings.TransformationSpace);
        InAttributeTessellationSettings->SetMaxAreaOfTessellatedValue(Settings.MaxAreaOfTessellatedValue);
        InAttributeTessellationSettings->SetMaxLengthOfTessellatedValue(Settings.MaxLengthOfTessellatedValue);
        InAttributeTessellationSettings->SetOnlyAllowOneLevelOfDifference(Settings.OnlyAllowOneLevelOfDifference);
        InAttributeTessellationSettings->SetMinTessellationLevel(Settings.MinTessellationLevel);
        InAttributeTessellationSettings->SetMaxTessellationLevel(Settings.MaxTessellationLevel);
        InAttributeTessellationSettings->SetMaxTotalValuesCount(Settings.MaxTotalValuesCount);
    }
    void SetMappingImageSettings(Simplygon::spMappingImageSettings InMappingImageSettings, const FMappingImageSettings& Settings) const
    {
        InMappingImageSettings->SetGenerateMappingImage(Settings.GenerateMappingImage);
        InMappingImageSettings->SetGenerateTexCoords(Settings.GenerateTexCoords);
        InMappingImageSettings->SetGenerateTangents(Settings.GenerateTangents);
        InMappingImageSettings->SetInputMaterialCount(Settings.InputMaterialCount);
        InMappingImageSettings->SetUseFullRetexturing(Settings.UseFullRetexturing);
        InMappingImageSettings->SetApplyNewMaterialIds(Settings.ApplyNewMaterialIds);
        InMappingImageSettings->SetOutputMaterialCount(Settings.OutputMaterialCount);
        InMappingImageSettings->SetReplaceMappingImages(Settings.ReplaceMappingImages);
        InMappingImageSettings->SetMaximumLayers(Settings.MaximumLayers);
        InMappingImageSettings->SetAllowTransparencyMapping(Settings.AllowTransparencyMapping);
        InMappingImageSettings->SetUseAutomaticTextureSize(Settings.UseAutomaticTextureSize);
        InMappingImageSettings->SetAutomaticTextureSizeMultiplier(Settings.AutomaticTextureSizeMultiplier);
        InMappingImageSettings->SetForcePower2Texture(Settings.ForcePower2Texture);
        InMappingImageSettings->SetOnlyParameterizeInvalidUVs(Settings.OnlyParameterizeInvalidUVs);
        InMappingImageSettings->SetTexCoordLevel(Settings.TexCoordLevel);
        InMappingImageSettings->SetTexCoordName(TCHAR_TO_ANSI(*Settings.TexCoordName));
        InMappingImageSettings->SetTexCoordGeneratorType((Simplygon::ETexcoordGeneratorType)Settings.TexCoordGeneratorType);

        int InputMaterialSettingsIndex = 0;
        InMappingImageSettings->SetInputMaterialCount(Settings.InputMaterialSettings.Num());
        for (FInputMaterialSettings SubSettings : Settings.InputMaterialSettings)
        {
            InMappingImageSettings->GetInputMaterialSettings(InputMaterialSettingsIndex)->SetMaterialMapping(SubSettings.MaterialMapping);
            InputMaterialSettingsIndex++;
        }

        int OutputMaterialSettingsIndex = 0;
        InMappingImageSettings->SetOutputMaterialCount(Settings.OutputMaterialSettings.Num());
        for (FOutputMaterialSettings SubSettings : Settings.OutputMaterialSettings)
        {
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetTextureWidth(SubSettings.TextureWidth);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetTextureHeight(SubSettings.TextureHeight);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetMultisamplingLevel(SubSettings.MultisamplingLevel);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetGutterSpace(SubSettings.GutterSpace);
            OutputMaterialSettingsIndex++;
        }

        InMappingImageSettings->GetChartAggregatorSettings()->SetChartAggregatorMode((Simplygon::EChartAggregatorMode)Settings.ChartAggregatorSettings.ChartAggregatorMode);
        InMappingImageSettings->GetChartAggregatorSettings()->SetSurfaceAreaScale((Simplygon::ESurfaceAreaScale)Settings.ChartAggregatorSettings.SurfaceAreaScale);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalTexCoordLevel(Settings.ChartAggregatorSettings.OriginalTexCoordLevel);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalTexCoordName(TCHAR_TO_ANSI(*Settings.ChartAggregatorSettings.OriginalTexCoordName));
        InMappingImageSettings->GetChartAggregatorSettings()->SetSeparateOverlappingCharts(Settings.ChartAggregatorSettings.SeparateOverlappingCharts);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalChartProportionsChannel(TCHAR_TO_ANSI(*Settings.ChartAggregatorSettings.OriginalChartProportionsChannel));
        InMappingImageSettings->GetChartAggregatorSettings()->SetLockUVRotation(Settings.ChartAggregatorSettings.LockUVRotation);

        InMappingImageSettings->GetParameterizerSettings()->SetMaxStretch(Settings.ParameterizerSettings.MaxStretch);
        InMappingImageSettings->GetParameterizerSettings()->SetLargeChartsImportance(Settings.ParameterizerSettings.LargeChartsImportance);
    }
#endif
};


USTRUCT(BlueprintType, Blueprintable)
struct SIMPLYGONUOBJECTS_API FBillboardCloudVegetationPipelineSettings : public FSimplygonPipelineSettings
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Billboard Cloud Settings")
    FBillboardCloudSettings BillboardCloudSettings;

    UPROPERTY()
    FAttributeTessellationSettings AttributeTessellationSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mapping Image Settings")
    FMappingImageSettings MappingImageSettings;

    UPROPERTY(EditAnywhere, Instanced, Category = "Material Baking")
    TArray<USimplygonMaterialCaster*> MaterialPropertyCasters;

    FBillboardCloudVegetationPipelineSettings() :
        BillboardCloudSettings(),
        AttributeTessellationSettings(),
        MappingImageSettings()

    {
           BillboardCloudSettings.BillboardMode = EBillboardMode::Foliage;
    }

    ~FBillboardCloudVegetationPipelineSettings() {}

#if ALLOW_SIMPLYGON
    virtual Simplygon::spPipeline CreatePipeline(Simplygon::ISimplygon* simplygon) override
    {
        Simplygon::spBillboardCloudVegetationPipeline BillboardCloudVegetationPipeline = simplygon->CreateBillboardCloudVegetationPipeline();

        Simplygon::spBillboardCloudSettings PipelineBillboardCloudSettings = BillboardCloudVegetationPipeline->GetBillboardCloudSettings();
        SetBillboardCloudSettings(PipelineBillboardCloudSettings, BillboardCloudSettings);

        Simplygon::spAttributeTessellationSettings PipelineAttributeTessellationSettings = BillboardCloudVegetationPipeline->GetAttributeTessellationSettings();
        SetAttributeTessellationSettings(PipelineAttributeTessellationSettings, AttributeTessellationSettings);

        Simplygon::spMappingImageSettings PipelineMappingImageSettings = BillboardCloudVegetationPipeline->GetMappingImageSettings();
        UpdateMappingImageSettings();
        SetMappingImageSettings(PipelineMappingImageSettings, MappingImageSettings);

        for (USimplygonMaterialCaster* Caster : MaterialPropertyCasters)
        {
            if(Caster)
            {
                BillboardCloudVegetationPipeline->AddMaterialCaster(Caster->CreateMaterialCaster(simplygon), 0);
            }
        }
        return BillboardCloudVegetationPipeline;
    }

private:
    void UpdateMappingImageSettings()
    {
       if(MaterialPropertyCasters.Num() > 0)
       {
           MappingImageSettings.GenerateMappingImage = true;
           MappingImageSettings.GenerateTexCoords = true;
           MappingImageSettings.GenerateTangents = true;
           MappingImageSettings.TexCoordLevel = SG_MATERIALBAKING_INDEX;
       }
       else
       {
           FMappingImageSettings DefaultSettings{};
           MappingImageSettings.GenerateMappingImage = DefaultSettings.GenerateMappingImage;
           MappingImageSettings.GenerateTexCoords = DefaultSettings.GenerateTexCoords;
           MappingImageSettings.GenerateTangents = DefaultSettings.GenerateTangents;
       }
    }
    void SetBillboardCloudSettings(Simplygon::spBillboardCloudSettings InBillboardCloudSettings, const FBillboardCloudSettings& Settings) const
    {
        InBillboardCloudSettings->SetBillboardMode((Simplygon::EBillboardMode)Settings.BillboardMode);
        InBillboardCloudSettings->SetFavorVerticalPlanes(Settings.FavorVerticalPlanes);
        InBillboardCloudSettings->SetTwoSided(Settings.TwoSided);
        InBillboardCloudSettings->SetUseVisibilityWeights(Settings.UseVisibilityWeights);
        InBillboardCloudSettings->SetBillboardDensity(Settings.BillboardDensity);
        InBillboardCloudSettings->SetMaxPlaneCount(Settings.MaxPlaneCount);
        InBillboardCloudSettings->SetGeometricComplexity(Settings.GeometricComplexity);
        InBillboardCloudSettings->SetUpVector((float*)&Settings.UpVector);

        InBillboardCloudSettings->GetFoliageSettings()->SetSeparateTrunkAndFoliage(Settings.FoliageSettings.SeparateTrunkAndFoliage);
        InBillboardCloudSettings->GetFoliageSettings()->SetSeparateFoliageTriangleRatio(Settings.FoliageSettings.SeparateFoliageTriangleRatio);
        InBillboardCloudSettings->GetFoliageSettings()->SetSeparateFoliageTriangleThreshold(Settings.FoliageSettings.SeparateFoliageTriangleThreshold);
        InBillboardCloudSettings->GetFoliageSettings()->SetSeparateFoliageAreaThreshold(Settings.FoliageSettings.SeparateFoliageAreaThreshold);
        InBillboardCloudSettings->GetFoliageSettings()->SetSeparateFoliageSizeThreshold(Settings.FoliageSettings.SeparateFoliageSizeThreshold);
        InBillboardCloudSettings->GetFoliageSettings()->SetTrunkReductionRatio(Settings.FoliageSettings.TrunkReductionRatio);
    }
    void SetAttributeTessellationSettings(Simplygon::spAttributeTessellationSettings InAttributeTessellationSettings, const FAttributeTessellationSettings& Settings) const
    {
        InAttributeTessellationSettings->SetEnableAttributeTessellation(Settings.EnableAttributeTessellation);
        InAttributeTessellationSettings->SetAttributeTessellationDensityMode((Simplygon::EAttributeTessellationDensityMode)Settings.AttributeTessellationDensityMode);
        InAttributeTessellationSettings->SetTransformationSpace((Simplygon::ETransformationSpace)Settings.TransformationSpace);
        InAttributeTessellationSettings->SetMaxAreaOfTessellatedValue(Settings.MaxAreaOfTessellatedValue);
        InAttributeTessellationSettings->SetMaxLengthOfTessellatedValue(Settings.MaxLengthOfTessellatedValue);
        InAttributeTessellationSettings->SetOnlyAllowOneLevelOfDifference(Settings.OnlyAllowOneLevelOfDifference);
        InAttributeTessellationSettings->SetMinTessellationLevel(Settings.MinTessellationLevel);
        InAttributeTessellationSettings->SetMaxTessellationLevel(Settings.MaxTessellationLevel);
        InAttributeTessellationSettings->SetMaxTotalValuesCount(Settings.MaxTotalValuesCount);
    }
    void SetMappingImageSettings(Simplygon::spMappingImageSettings InMappingImageSettings, const FMappingImageSettings& Settings) const
    {
        InMappingImageSettings->SetGenerateMappingImage(Settings.GenerateMappingImage);
        InMappingImageSettings->SetGenerateTexCoords(Settings.GenerateTexCoords);
        InMappingImageSettings->SetGenerateTangents(Settings.GenerateTangents);
        InMappingImageSettings->SetInputMaterialCount(Settings.InputMaterialCount);
        InMappingImageSettings->SetUseFullRetexturing(Settings.UseFullRetexturing);
        InMappingImageSettings->SetApplyNewMaterialIds(Settings.ApplyNewMaterialIds);
        InMappingImageSettings->SetOutputMaterialCount(Settings.OutputMaterialCount);
        InMappingImageSettings->SetReplaceMappingImages(Settings.ReplaceMappingImages);
        InMappingImageSettings->SetMaximumLayers(Settings.MaximumLayers);
        InMappingImageSettings->SetAllowTransparencyMapping(Settings.AllowTransparencyMapping);
        InMappingImageSettings->SetUseAutomaticTextureSize(Settings.UseAutomaticTextureSize);
        InMappingImageSettings->SetAutomaticTextureSizeMultiplier(Settings.AutomaticTextureSizeMultiplier);
        InMappingImageSettings->SetForcePower2Texture(Settings.ForcePower2Texture);
        InMappingImageSettings->SetOnlyParameterizeInvalidUVs(Settings.OnlyParameterizeInvalidUVs);
        InMappingImageSettings->SetTexCoordLevel(Settings.TexCoordLevel);
        InMappingImageSettings->SetTexCoordName(TCHAR_TO_ANSI(*Settings.TexCoordName));
        InMappingImageSettings->SetTexCoordGeneratorType((Simplygon::ETexcoordGeneratorType)Settings.TexCoordGeneratorType);

        int InputMaterialSettingsIndex = 0;
        InMappingImageSettings->SetInputMaterialCount(Settings.InputMaterialSettings.Num());
        for (FInputMaterialSettings SubSettings : Settings.InputMaterialSettings)
        {
            InMappingImageSettings->GetInputMaterialSettings(InputMaterialSettingsIndex)->SetMaterialMapping(SubSettings.MaterialMapping);
            InputMaterialSettingsIndex++;
        }

        int OutputMaterialSettingsIndex = 0;
        InMappingImageSettings->SetOutputMaterialCount(Settings.OutputMaterialSettings.Num());
        for (FOutputMaterialSettings SubSettings : Settings.OutputMaterialSettings)
        {
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetTextureWidth(SubSettings.TextureWidth);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetTextureHeight(SubSettings.TextureHeight);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetMultisamplingLevel(SubSettings.MultisamplingLevel);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetGutterSpace(SubSettings.GutterSpace);
            OutputMaterialSettingsIndex++;
        }

        InMappingImageSettings->GetChartAggregatorSettings()->SetChartAggregatorMode((Simplygon::EChartAggregatorMode)Settings.ChartAggregatorSettings.ChartAggregatorMode);
        InMappingImageSettings->GetChartAggregatorSettings()->SetSurfaceAreaScale((Simplygon::ESurfaceAreaScale)Settings.ChartAggregatorSettings.SurfaceAreaScale);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalTexCoordLevel(Settings.ChartAggregatorSettings.OriginalTexCoordLevel);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalTexCoordName(TCHAR_TO_ANSI(*Settings.ChartAggregatorSettings.OriginalTexCoordName));
        InMappingImageSettings->GetChartAggregatorSettings()->SetSeparateOverlappingCharts(Settings.ChartAggregatorSettings.SeparateOverlappingCharts);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalChartProportionsChannel(TCHAR_TO_ANSI(*Settings.ChartAggregatorSettings.OriginalChartProportionsChannel));
        InMappingImageSettings->GetChartAggregatorSettings()->SetLockUVRotation(Settings.ChartAggregatorSettings.LockUVRotation);

        InMappingImageSettings->GetParameterizerSettings()->SetMaxStretch(Settings.ParameterizerSettings.MaxStretch);
        InMappingImageSettings->GetParameterizerSettings()->SetLargeChartsImportance(Settings.ParameterizerSettings.LargeChartsImportance);
    }
#endif
};


USTRUCT(BlueprintType, Blueprintable)
struct SIMPLYGONUOBJECTS_API FFlipbookPipelineSettings : public FSimplygonPipelineSettings
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Flipbook Settings")
    FFlipbookSettings FlipbookSettings;

    UPROPERTY()
    FAttributeTessellationSettings AttributeTessellationSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mapping Image Settings")
    FMappingImageSettings MappingImageSettings;

    UPROPERTY(EditAnywhere, Instanced, Category = "Material Baking")
    TArray<USimplygonMaterialCaster*> MaterialPropertyCasters;

    FFlipbookPipelineSettings() :
        FlipbookSettings(),
        AttributeTessellationSettings(),
        MappingImageSettings()

    {
    }

    ~FFlipbookPipelineSettings() {}

#if ALLOW_SIMPLYGON
    virtual Simplygon::spPipeline CreatePipeline(Simplygon::ISimplygon* simplygon) override
    {
        Simplygon::spFlipbookPipeline FlipbookPipeline = simplygon->CreateFlipbookPipeline();

        Simplygon::spFlipbookSettings PipelineFlipbookSettings = FlipbookPipeline->GetFlipbookSettings();
        SetFlipbookSettings(PipelineFlipbookSettings, FlipbookSettings);

        Simplygon::spAttributeTessellationSettings PipelineAttributeTessellationSettings = FlipbookPipeline->GetAttributeTessellationSettings();
        SetAttributeTessellationSettings(PipelineAttributeTessellationSettings, AttributeTessellationSettings);

        Simplygon::spMappingImageSettings PipelineMappingImageSettings = FlipbookPipeline->GetMappingImageSettings();
        UpdateMappingImageSettings();
        SetMappingImageSettings(PipelineMappingImageSettings, MappingImageSettings);

        for (USimplygonMaterialCaster* Caster : MaterialPropertyCasters)
        {
            if(Caster)
            {
                FlipbookPipeline->AddMaterialCaster(Caster->CreateMaterialCaster(simplygon), 0);
            }
        }
        return FlipbookPipeline;
    }

private:
    void UpdateMappingImageSettings()
    {
       if(MaterialPropertyCasters.Num() > 0)
       {
           MappingImageSettings.GenerateMappingImage = true;
           MappingImageSettings.GenerateTexCoords = true;
           MappingImageSettings.GenerateTangents = true;
           MappingImageSettings.TexCoordLevel = SG_MATERIALBAKING_INDEX;
       }
       else
       {
           FMappingImageSettings DefaultSettings{};
           MappingImageSettings.GenerateMappingImage = DefaultSettings.GenerateMappingImage;
           MappingImageSettings.GenerateTexCoords = DefaultSettings.GenerateTexCoords;
           MappingImageSettings.GenerateTangents = DefaultSettings.GenerateTangents;
       }
    }
    void SetFlipbookSettings(Simplygon::spFlipbookSettings InFlipbookSettings, const FFlipbookSettings& Settings) const
    {
        InFlipbookSettings->SetNumberOfViews(Settings.NumberOfViews);
        InFlipbookSettings->SetViewDirection((float*)&Settings.ViewDirection);
        InFlipbookSettings->SetUpVector((float*)&Settings.UpVector);
    }
    void SetAttributeTessellationSettings(Simplygon::spAttributeTessellationSettings InAttributeTessellationSettings, const FAttributeTessellationSettings& Settings) const
    {
        InAttributeTessellationSettings->SetEnableAttributeTessellation(Settings.EnableAttributeTessellation);
        InAttributeTessellationSettings->SetAttributeTessellationDensityMode((Simplygon::EAttributeTessellationDensityMode)Settings.AttributeTessellationDensityMode);
        InAttributeTessellationSettings->SetTransformationSpace((Simplygon::ETransformationSpace)Settings.TransformationSpace);
        InAttributeTessellationSettings->SetMaxAreaOfTessellatedValue(Settings.MaxAreaOfTessellatedValue);
        InAttributeTessellationSettings->SetMaxLengthOfTessellatedValue(Settings.MaxLengthOfTessellatedValue);
        InAttributeTessellationSettings->SetOnlyAllowOneLevelOfDifference(Settings.OnlyAllowOneLevelOfDifference);
        InAttributeTessellationSettings->SetMinTessellationLevel(Settings.MinTessellationLevel);
        InAttributeTessellationSettings->SetMaxTessellationLevel(Settings.MaxTessellationLevel);
        InAttributeTessellationSettings->SetMaxTotalValuesCount(Settings.MaxTotalValuesCount);
    }
    void SetMappingImageSettings(Simplygon::spMappingImageSettings InMappingImageSettings, const FMappingImageSettings& Settings) const
    {
        InMappingImageSettings->SetGenerateMappingImage(Settings.GenerateMappingImage);
        InMappingImageSettings->SetGenerateTexCoords(Settings.GenerateTexCoords);
        InMappingImageSettings->SetGenerateTangents(Settings.GenerateTangents);
        InMappingImageSettings->SetInputMaterialCount(Settings.InputMaterialCount);
        InMappingImageSettings->SetUseFullRetexturing(Settings.UseFullRetexturing);
        InMappingImageSettings->SetApplyNewMaterialIds(Settings.ApplyNewMaterialIds);
        InMappingImageSettings->SetOutputMaterialCount(Settings.OutputMaterialCount);
        InMappingImageSettings->SetReplaceMappingImages(Settings.ReplaceMappingImages);
        InMappingImageSettings->SetMaximumLayers(Settings.MaximumLayers);
        InMappingImageSettings->SetAllowTransparencyMapping(Settings.AllowTransparencyMapping);
        InMappingImageSettings->SetUseAutomaticTextureSize(Settings.UseAutomaticTextureSize);
        InMappingImageSettings->SetAutomaticTextureSizeMultiplier(Settings.AutomaticTextureSizeMultiplier);
        InMappingImageSettings->SetForcePower2Texture(Settings.ForcePower2Texture);
        InMappingImageSettings->SetOnlyParameterizeInvalidUVs(Settings.OnlyParameterizeInvalidUVs);
        InMappingImageSettings->SetTexCoordLevel(Settings.TexCoordLevel);
        InMappingImageSettings->SetTexCoordName(TCHAR_TO_ANSI(*Settings.TexCoordName));
        InMappingImageSettings->SetTexCoordGeneratorType((Simplygon::ETexcoordGeneratorType)Settings.TexCoordGeneratorType);

        int InputMaterialSettingsIndex = 0;
        InMappingImageSettings->SetInputMaterialCount(Settings.InputMaterialSettings.Num());
        for (FInputMaterialSettings SubSettings : Settings.InputMaterialSettings)
        {
            InMappingImageSettings->GetInputMaterialSettings(InputMaterialSettingsIndex)->SetMaterialMapping(SubSettings.MaterialMapping);
            InputMaterialSettingsIndex++;
        }

        int OutputMaterialSettingsIndex = 0;
        InMappingImageSettings->SetOutputMaterialCount(Settings.OutputMaterialSettings.Num());
        for (FOutputMaterialSettings SubSettings : Settings.OutputMaterialSettings)
        {
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetTextureWidth(SubSettings.TextureWidth);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetTextureHeight(SubSettings.TextureHeight);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetMultisamplingLevel(SubSettings.MultisamplingLevel);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetGutterSpace(SubSettings.GutterSpace);
            OutputMaterialSettingsIndex++;
        }

        InMappingImageSettings->GetChartAggregatorSettings()->SetChartAggregatorMode((Simplygon::EChartAggregatorMode)Settings.ChartAggregatorSettings.ChartAggregatorMode);
        InMappingImageSettings->GetChartAggregatorSettings()->SetSurfaceAreaScale((Simplygon::ESurfaceAreaScale)Settings.ChartAggregatorSettings.SurfaceAreaScale);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalTexCoordLevel(Settings.ChartAggregatorSettings.OriginalTexCoordLevel);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalTexCoordName(TCHAR_TO_ANSI(*Settings.ChartAggregatorSettings.OriginalTexCoordName));
        InMappingImageSettings->GetChartAggregatorSettings()->SetSeparateOverlappingCharts(Settings.ChartAggregatorSettings.SeparateOverlappingCharts);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalChartProportionsChannel(TCHAR_TO_ANSI(*Settings.ChartAggregatorSettings.OriginalChartProportionsChannel));
        InMappingImageSettings->GetChartAggregatorSettings()->SetLockUVRotation(Settings.ChartAggregatorSettings.LockUVRotation);

        InMappingImageSettings->GetParameterizerSettings()->SetMaxStretch(Settings.ParameterizerSettings.MaxStretch);
        InMappingImageSettings->GetParameterizerSettings()->SetLargeChartsImportance(Settings.ParameterizerSettings.LargeChartsImportance);
    }
#endif
};


USTRUCT(BlueprintType, Blueprintable)
struct SIMPLYGONUOBJECTS_API FImpostorFromSingleViewPipelineSettings : public FSimplygonPipelineSettings
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Impostor From Single View Settings")
    FImpostorFromSingleViewSettings ImpostorFromSingleViewSettings;

    UPROPERTY()
    FAttributeTessellationSettings AttributeTessellationSettings;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mapping Image Settings")
    FMappingImageSettings MappingImageSettings;

    UPROPERTY(EditAnywhere, Instanced, Category = "Material Baking")
    TArray<USimplygonMaterialCaster*> MaterialPropertyCasters;

    FImpostorFromSingleViewPipelineSettings() :
        ImpostorFromSingleViewSettings(),
        AttributeTessellationSettings(),
        MappingImageSettings()

    {
    }

    ~FImpostorFromSingleViewPipelineSettings() {}

#if ALLOW_SIMPLYGON
    virtual Simplygon::spPipeline CreatePipeline(Simplygon::ISimplygon* simplygon) override
    {
        Simplygon::spImpostorFromSingleViewPipeline ImpostorFromSingleViewPipeline = simplygon->CreateImpostorFromSingleViewPipeline();

        Simplygon::spImpostorFromSingleViewSettings PipelineImpostorFromSingleViewSettings = ImpostorFromSingleViewPipeline->GetImpostorFromSingleViewSettings();
        SetImpostorFromSingleViewSettings(PipelineImpostorFromSingleViewSettings, ImpostorFromSingleViewSettings);

        Simplygon::spAttributeTessellationSettings PipelineAttributeTessellationSettings = ImpostorFromSingleViewPipeline->GetAttributeTessellationSettings();
        SetAttributeTessellationSettings(PipelineAttributeTessellationSettings, AttributeTessellationSettings);

        Simplygon::spMappingImageSettings PipelineMappingImageSettings = ImpostorFromSingleViewPipeline->GetMappingImageSettings();
        UpdateMappingImageSettings();
        SetMappingImageSettings(PipelineMappingImageSettings, MappingImageSettings);

        for (USimplygonMaterialCaster* Caster : MaterialPropertyCasters)
        {
            if(Caster)
            {
                ImpostorFromSingleViewPipeline->AddMaterialCaster(Caster->CreateMaterialCaster(simplygon), 0);
            }
        }
        return ImpostorFromSingleViewPipeline;
    }

private:
    void UpdateMappingImageSettings()
    {
       if(MaterialPropertyCasters.Num() > 0)
       {
           MappingImageSettings.GenerateMappingImage = true;
           MappingImageSettings.GenerateTexCoords = true;
           MappingImageSettings.GenerateTangents = true;
           MappingImageSettings.TexCoordLevel = SG_MATERIALBAKING_INDEX;
       }
       else
       {
           FMappingImageSettings DefaultSettings{};
           MappingImageSettings.GenerateMappingImage = DefaultSettings.GenerateMappingImage;
           MappingImageSettings.GenerateTexCoords = DefaultSettings.GenerateTexCoords;
           MappingImageSettings.GenerateTangents = DefaultSettings.GenerateTangents;
       }
    }
    void SetImpostorFromSingleViewSettings(Simplygon::spImpostorFromSingleViewSettings InImpostorFromSingleViewSettings, const FImpostorFromSingleViewSettings& Settings) const
    {
        InImpostorFromSingleViewSettings->SetUseTightFitting(Settings.UseTightFitting);
        InImpostorFromSingleViewSettings->SetTightFittingDepthOffset(Settings.TightFittingDepthOffset);
        InImpostorFromSingleViewSettings->SetTwoSided(Settings.TwoSided);
        InImpostorFromSingleViewSettings->SetViewDirection((float*)&Settings.ViewDirection);
        InImpostorFromSingleViewSettings->SetTexCoordPadding(Settings.TexCoordPadding);
    }
    void SetAttributeTessellationSettings(Simplygon::spAttributeTessellationSettings InAttributeTessellationSettings, const FAttributeTessellationSettings& Settings) const
    {
        InAttributeTessellationSettings->SetEnableAttributeTessellation(Settings.EnableAttributeTessellation);
        InAttributeTessellationSettings->SetAttributeTessellationDensityMode((Simplygon::EAttributeTessellationDensityMode)Settings.AttributeTessellationDensityMode);
        InAttributeTessellationSettings->SetTransformationSpace((Simplygon::ETransformationSpace)Settings.TransformationSpace);
        InAttributeTessellationSettings->SetMaxAreaOfTessellatedValue(Settings.MaxAreaOfTessellatedValue);
        InAttributeTessellationSettings->SetMaxLengthOfTessellatedValue(Settings.MaxLengthOfTessellatedValue);
        InAttributeTessellationSettings->SetOnlyAllowOneLevelOfDifference(Settings.OnlyAllowOneLevelOfDifference);
        InAttributeTessellationSettings->SetMinTessellationLevel(Settings.MinTessellationLevel);
        InAttributeTessellationSettings->SetMaxTessellationLevel(Settings.MaxTessellationLevel);
        InAttributeTessellationSettings->SetMaxTotalValuesCount(Settings.MaxTotalValuesCount);
    }
    void SetMappingImageSettings(Simplygon::spMappingImageSettings InMappingImageSettings, const FMappingImageSettings& Settings) const
    {
        InMappingImageSettings->SetGenerateMappingImage(Settings.GenerateMappingImage);
        InMappingImageSettings->SetGenerateTexCoords(Settings.GenerateTexCoords);
        InMappingImageSettings->SetGenerateTangents(Settings.GenerateTangents);
        InMappingImageSettings->SetInputMaterialCount(Settings.InputMaterialCount);
        InMappingImageSettings->SetUseFullRetexturing(Settings.UseFullRetexturing);
        InMappingImageSettings->SetApplyNewMaterialIds(Settings.ApplyNewMaterialIds);
        InMappingImageSettings->SetOutputMaterialCount(Settings.OutputMaterialCount);
        InMappingImageSettings->SetReplaceMappingImages(Settings.ReplaceMappingImages);
        InMappingImageSettings->SetMaximumLayers(Settings.MaximumLayers);
        InMappingImageSettings->SetAllowTransparencyMapping(Settings.AllowTransparencyMapping);
        InMappingImageSettings->SetUseAutomaticTextureSize(Settings.UseAutomaticTextureSize);
        InMappingImageSettings->SetAutomaticTextureSizeMultiplier(Settings.AutomaticTextureSizeMultiplier);
        InMappingImageSettings->SetForcePower2Texture(Settings.ForcePower2Texture);
        InMappingImageSettings->SetOnlyParameterizeInvalidUVs(Settings.OnlyParameterizeInvalidUVs);
        InMappingImageSettings->SetTexCoordLevel(Settings.TexCoordLevel);
        InMappingImageSettings->SetTexCoordName(TCHAR_TO_ANSI(*Settings.TexCoordName));
        InMappingImageSettings->SetTexCoordGeneratorType((Simplygon::ETexcoordGeneratorType)Settings.TexCoordGeneratorType);

        int InputMaterialSettingsIndex = 0;
        InMappingImageSettings->SetInputMaterialCount(Settings.InputMaterialSettings.Num());
        for (FInputMaterialSettings SubSettings : Settings.InputMaterialSettings)
        {
            InMappingImageSettings->GetInputMaterialSettings(InputMaterialSettingsIndex)->SetMaterialMapping(SubSettings.MaterialMapping);
            InputMaterialSettingsIndex++;
        }

        int OutputMaterialSettingsIndex = 0;
        InMappingImageSettings->SetOutputMaterialCount(Settings.OutputMaterialSettings.Num());
        for (FOutputMaterialSettings SubSettings : Settings.OutputMaterialSettings)
        {
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetTextureWidth(SubSettings.TextureWidth);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetTextureHeight(SubSettings.TextureHeight);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetMultisamplingLevel(SubSettings.MultisamplingLevel);
            InMappingImageSettings->GetOutputMaterialSettings(OutputMaterialSettingsIndex)->SetGutterSpace(SubSettings.GutterSpace);
            OutputMaterialSettingsIndex++;
        }

        InMappingImageSettings->GetChartAggregatorSettings()->SetChartAggregatorMode((Simplygon::EChartAggregatorMode)Settings.ChartAggregatorSettings.ChartAggregatorMode);
        InMappingImageSettings->GetChartAggregatorSettings()->SetSurfaceAreaScale((Simplygon::ESurfaceAreaScale)Settings.ChartAggregatorSettings.SurfaceAreaScale);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalTexCoordLevel(Settings.ChartAggregatorSettings.OriginalTexCoordLevel);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalTexCoordName(TCHAR_TO_ANSI(*Settings.ChartAggregatorSettings.OriginalTexCoordName));
        InMappingImageSettings->GetChartAggregatorSettings()->SetSeparateOverlappingCharts(Settings.ChartAggregatorSettings.SeparateOverlappingCharts);
        InMappingImageSettings->GetChartAggregatorSettings()->SetOriginalChartProportionsChannel(TCHAR_TO_ANSI(*Settings.ChartAggregatorSettings.OriginalChartProportionsChannel));
        InMappingImageSettings->GetChartAggregatorSettings()->SetLockUVRotation(Settings.ChartAggregatorSettings.LockUVRotation);

        InMappingImageSettings->GetParameterizerSettings()->SetMaxStretch(Settings.ParameterizerSettings.MaxStretch);
        InMappingImageSettings->GetParameterizerSettings()->SetLargeChartsImportance(Settings.ParameterizerSettings.LargeChartsImportance);
    }
#endif
};


USTRUCT(BlueprintType, Blueprintable)
struct SIMPLYGONUOBJECTS_API FHighDensityMeshReductionPipelineSettings : public FSimplygonPipelineSettings
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "High Density Mesh Reduction Settings")
    FHighDensityMeshReductionSettings HighDensityMeshReductionSettings;

    FHighDensityMeshReductionPipelineSettings() :
        HighDensityMeshReductionSettings()

    {
    }

    ~FHighDensityMeshReductionPipelineSettings() {}

#if ALLOW_SIMPLYGON
    virtual Simplygon::spPipeline CreatePipeline(Simplygon::ISimplygon* simplygon) override
    {
        Simplygon::spHighDensityMeshReductionPipeline HighDensityMeshReductionPipeline = simplygon->CreateHighDensityMeshReductionPipeline();

        Simplygon::spHighDensityMeshReductionSettings PipelineHighDensityMeshReductionSettings = HighDensityMeshReductionPipeline->GetHighDensityMeshReductionSettings();
        SetHighDensityMeshReductionSettings(PipelineHighDensityMeshReductionSettings, HighDensityMeshReductionSettings);

        return HighDensityMeshReductionPipeline;
    }

private:
    void SetHighDensityMeshReductionSettings(Simplygon::spHighDensityMeshReductionSettings InHighDensityMeshReductionSettings, const FHighDensityMeshReductionSettings& Settings) const
    {
        InHighDensityMeshReductionSettings->SetOnScreenSizeEnabled(Settings.OnScreenSizeEnabled);
        InHighDensityMeshReductionSettings->SetOnScreenSize(Settings.OnScreenSize);
        InHighDensityMeshReductionSettings->SetMaxDeviationEnabled(Settings.MaxDeviationEnabled);
        InHighDensityMeshReductionSettings->SetMaxDeviation(Settings.MaxDeviation);
        InHighDensityMeshReductionSettings->SetStopCondition((Simplygon::EStopCondition)Settings.StopCondition);
        InHighDensityMeshReductionSettings->SetProcessSelectionSetName(TCHAR_TO_ANSI(*Settings.ProcessSelectionSetName));
    }
#endif
};

UCLASS(BlueprintType, Blueprintable)
class SIMPLYGONUOBJECTS_API USimplygonColorCaster : public USimplygonMaterialCaster
{
    GENERATED_BODY()

public:

    UPROPERTY(EditAnywhere, BlueprintReadWrite,Category = "Color Caster Settings")
    FColorCasterSettings ColorCasterSettings;

    USimplygonColorCaster() :
        ColorCasterSettings()
    {
    }

#if ALLOW_SIMPLYGON
    virtual Simplygon::spMaterialCaster CreateMaterialCaster(Simplygon::ISimplygon* simplygon) override
    {
        Simplygon::spColorCaster ColorCaster = simplygon->CreateColorCaster();

        Simplygon::spColorCasterSettings MaterialCasterColorCasterSettings = ColorCaster->GetColorCasterSettings();
        SetColorCasterSettings(MaterialCasterColorCasterSettings, ColorCasterSettings);

        return ColorCaster;
    }

#endif


private:
#if ALLOW_SIMPLYGON
    void SetColorCasterSettings(Simplygon::spColorCasterSettings InColorCasterSettings, const FColorCasterSettings& Settings) const
    {
        InColorCasterSettings->SetMaterialChannel(TCHAR_TO_ANSI(*Settings.MaterialChannel));
        InColorCasterSettings->SetOpacityChannelComponent((Simplygon::EColorComponent)Settings.OpacityChannelComponent);
        InColorCasterSettings->SetDitherType((Simplygon::EDitherPatterns)Settings.DitherType);
        InColorCasterSettings->SetFillMode((Simplygon::EAtlasFillMode)Settings.FillMode);
        InColorCasterSettings->SetOpacityChannel(TCHAR_TO_ANSI(*Settings.OpacityChannel));
        InColorCasterSettings->SetUseMultisampling(Settings.UseMultisampling);
        InColorCasterSettings->SetBakeOpacityInAlpha(Settings.BakeOpacityInAlpha);
        InColorCasterSettings->SetOutputImageFileFormat((Simplygon::EImageOutputFormat)Settings.OutputImageFileFormat);
        InColorCasterSettings->SetOutputDDSCompressionType((Simplygon::EDDSCompressionType)Settings.OutputDDSCompressionType);
        InColorCasterSettings->SetDilation(Settings.Dilation);
        InColorCasterSettings->SetOutputOpacityType((Simplygon::EOpacityType)Settings.OutputOpacityType);
        InColorCasterSettings->SetOutputPixelFormat((Simplygon::EPixelFormat)Settings.OutputPixelFormat);
        InColorCasterSettings->SetSkipCastingIfNoInputChannel(Settings.SkipCastingIfNoInputChannel);
        InColorCasterSettings->SetOutputSRGB(Settings.OutputSRGB);
    }
#endif

};

UCLASS(BlueprintType, Blueprintable)
class SIMPLYGONUOBJECTS_API USimplygonOpacityCaster : public USimplygonMaterialCaster
{
    GENERATED_BODY()

public:

    UPROPERTY(EditAnywhere, BlueprintReadWrite,Category = "Opacity Caster Settings")
    FOpacityCasterSettings OpacityCasterSettings;

    USimplygonOpacityCaster() :
        OpacityCasterSettings()
    {
    }

#if ALLOW_SIMPLYGON
    virtual Simplygon::spMaterialCaster CreateMaterialCaster(Simplygon::ISimplygon* simplygon) override
    {
        Simplygon::spOpacityCaster OpacityCaster = simplygon->CreateOpacityCaster();

        Simplygon::spOpacityCasterSettings MaterialCasterOpacityCasterSettings = OpacityCaster->GetOpacityCasterSettings();
        SetOpacityCasterSettings(MaterialCasterOpacityCasterSettings, OpacityCasterSettings);

        return OpacityCaster;
    }

#endif


private:
#if ALLOW_SIMPLYGON
    void SetOpacityCasterSettings(Simplygon::spOpacityCasterSettings InOpacityCasterSettings, const FOpacityCasterSettings& Settings) const
    {
        InOpacityCasterSettings->SetMaterialChannel(TCHAR_TO_ANSI(*Settings.MaterialChannel));
        InOpacityCasterSettings->SetOpacityChannelComponent((Simplygon::EColorComponent)Settings.OpacityChannelComponent);
        InOpacityCasterSettings->SetDitherType((Simplygon::EDitherPatterns)Settings.DitherType);
        InOpacityCasterSettings->SetFillMode((Simplygon::EAtlasFillMode)Settings.FillMode);
        InOpacityCasterSettings->SetOpacityChannel(TCHAR_TO_ANSI(*Settings.OpacityChannel));
        InOpacityCasterSettings->SetUseMultisampling(Settings.UseMultisampling);
        InOpacityCasterSettings->SetOutputSRGB(Settings.OutputSRGB);
        InOpacityCasterSettings->SetOutputImageFileFormat((Simplygon::EImageOutputFormat)Settings.OutputImageFileFormat);
        InOpacityCasterSettings->SetOutputDDSCompressionType((Simplygon::EDDSCompressionType)Settings.OutputDDSCompressionType);
        InOpacityCasterSettings->SetDilation(Settings.Dilation);
        InOpacityCasterSettings->SetOutputOpacityType((Simplygon::EOpacityType)Settings.OutputOpacityType);
        InOpacityCasterSettings->SetOutputPixelFormat((Simplygon::EPixelFormat)Settings.OutputPixelFormat);
        InOpacityCasterSettings->SetOutputToTessellatedAttributes(Settings.OutputToTessellatedAttributes);
    }
#endif

};

UCLASS(BlueprintType, Blueprintable)
class SIMPLYGONUOBJECTS_API USimplygonNormalCaster : public USimplygonMaterialCaster
{
    GENERATED_BODY()

public:

    UPROPERTY(EditAnywhere, BlueprintReadWrite,Category = "Normal Caster Settings")
    FNormalCasterSettings NormalCasterSettings;

    USimplygonNormalCaster() :
        NormalCasterSettings()
    {
    }

#if ALLOW_SIMPLYGON
    virtual Simplygon::spMaterialCaster CreateMaterialCaster(Simplygon::ISimplygon* simplygon) override
    {
        Simplygon::spNormalCaster NormalCaster = simplygon->CreateNormalCaster();

        Simplygon::spNormalCasterSettings MaterialCasterNormalCasterSettings = NormalCaster->GetNormalCasterSettings();
        SetNormalCasterSettings(MaterialCasterNormalCasterSettings, NormalCasterSettings);

        return NormalCaster;
    }

#endif


private:
#if ALLOW_SIMPLYGON
    void SetNormalCasterSettings(Simplygon::spNormalCasterSettings InNormalCasterSettings, const FNormalCasterSettings& Settings) const
    {
        InNormalCasterSettings->SetMaterialChannel(TCHAR_TO_ANSI(*Settings.MaterialChannel));
        InNormalCasterSettings->SetOpacityChannelComponent((Simplygon::EColorComponent)Settings.OpacityChannelComponent);
        InNormalCasterSettings->SetDitherType((Simplygon::EDitherPatterns)Settings.DitherType);
        InNormalCasterSettings->SetFillMode((Simplygon::EAtlasFillMode)Settings.FillMode);
        InNormalCasterSettings->SetOpacityChannel(TCHAR_TO_ANSI(*Settings.OpacityChannel));
        InNormalCasterSettings->SetUseMultisampling(Settings.UseMultisampling);
        InNormalCasterSettings->SetFlipBackfacingNormals(Settings.FlipBackfacingNormals);
        InNormalCasterSettings->SetOutputImageFileFormat((Simplygon::EImageOutputFormat)Settings.OutputImageFileFormat);
        InNormalCasterSettings->SetOutputDDSCompressionType((Simplygon::EDDSCompressionType)Settings.OutputDDSCompressionType);
        InNormalCasterSettings->SetDilation(Settings.Dilation);
        InNormalCasterSettings->SetGenerateTangentSpaceNormals(Settings.GenerateTangentSpaceNormals);
        InNormalCasterSettings->SetOutputPixelFormat((Simplygon::EPixelFormat)Settings.OutputPixelFormat);
        InNormalCasterSettings->SetFlipGreen(Settings.FlipGreen);
        InNormalCasterSettings->SetCalculateBitangentPerFragment(Settings.CalculateBitangentPerFragment);
        InNormalCasterSettings->SetNormalizeInterpolatedTangentSpace(Settings.NormalizeInterpolatedTangentSpace);
    }
#endif

};

UCLASS(BlueprintType, Blueprintable)
class SIMPLYGONUOBJECTS_API USimplygonDisplacementCaster : public USimplygonMaterialCaster
{
    GENERATED_BODY()

public:

    UPROPERTY(EditAnywhere, BlueprintReadWrite,Category = "Displacement Caster Settings")
    FDisplacementCasterSettings DisplacementCasterSettings;

    USimplygonDisplacementCaster() :
        DisplacementCasterSettings()
    {
    }

#if ALLOW_SIMPLYGON
    virtual Simplygon::spMaterialCaster CreateMaterialCaster(Simplygon::ISimplygon* simplygon) override
    {
        Simplygon::spDisplacementCaster DisplacementCaster = simplygon->CreateDisplacementCaster();

        Simplygon::spDisplacementCasterSettings MaterialCasterDisplacementCasterSettings = DisplacementCaster->GetDisplacementCasterSettings();
        SetDisplacementCasterSettings(MaterialCasterDisplacementCasterSettings, DisplacementCasterSettings);

        return DisplacementCaster;
    }

#endif


private:
#if ALLOW_SIMPLYGON
    void SetDisplacementCasterSettings(Simplygon::spDisplacementCasterSettings InDisplacementCasterSettings, const FDisplacementCasterSettings& Settings) const
    {
        InDisplacementCasterSettings->SetMaterialChannel(TCHAR_TO_ANSI(*Settings.MaterialChannel));
        InDisplacementCasterSettings->SetOpacityChannelComponent((Simplygon::EColorComponent)Settings.OpacityChannelComponent);
        InDisplacementCasterSettings->SetDitherType((Simplygon::EDitherPatterns)Settings.DitherType);
        InDisplacementCasterSettings->SetFillMode((Simplygon::EAtlasFillMode)Settings.FillMode);
        InDisplacementCasterSettings->SetOpacityChannel(TCHAR_TO_ANSI(*Settings.OpacityChannel));
        InDisplacementCasterSettings->SetUseMultisampling(Settings.UseMultisampling);
        InDisplacementCasterSettings->SetDistanceScaling(Settings.DistanceScaling);
        InDisplacementCasterSettings->SetOutputImageFileFormat((Simplygon::EImageOutputFormat)Settings.OutputImageFileFormat);
        InDisplacementCasterSettings->SetOutputDDSCompressionType((Simplygon::EDDSCompressionType)Settings.OutputDDSCompressionType);
        InDisplacementCasterSettings->SetDilation(Settings.Dilation);
        InDisplacementCasterSettings->SetGenerateScalarDisplacement(Settings.GenerateScalarDisplacement);
        InDisplacementCasterSettings->SetOutputPixelFormat((Simplygon::EPixelFormat)Settings.OutputPixelFormat);
        InDisplacementCasterSettings->SetGenerateTangentSpaceDisplacement(Settings.GenerateTangentSpaceDisplacement);
        InDisplacementCasterSettings->SetNormalMapTexCoordLevel(Settings.NormalMapTexCoordLevel);
        InDisplacementCasterSettings->SetOutputToTessellatedAttributes(Settings.OutputToTessellatedAttributes);
    }
#endif

};

UCLASS(BlueprintType, Blueprintable)
class SIMPLYGONUOBJECTS_API USimplygonAmbientOcclusionCaster : public USimplygonMaterialCaster
{
    GENERATED_BODY()

public:

    UPROPERTY(EditAnywhere, BlueprintReadWrite,Category = "Ambient Occlusion Caster Settings")
    FAmbientOcclusionCasterSettings AmbientOcclusionCasterSettings;

    USimplygonAmbientOcclusionCaster() :
        AmbientOcclusionCasterSettings()
    {
    }

#if ALLOW_SIMPLYGON
    virtual Simplygon::spMaterialCaster CreateMaterialCaster(Simplygon::ISimplygon* simplygon) override
    {
        Simplygon::spAmbientOcclusionCaster AmbientOcclusionCaster = simplygon->CreateAmbientOcclusionCaster();

        Simplygon::spAmbientOcclusionCasterSettings MaterialCasterAmbientOcclusionCasterSettings = AmbientOcclusionCaster->GetAmbientOcclusionCasterSettings();
        SetAmbientOcclusionCasterSettings(MaterialCasterAmbientOcclusionCasterSettings, AmbientOcclusionCasterSettings);

        return AmbientOcclusionCaster;
    }

#endif


private:
#if ALLOW_SIMPLYGON
    void SetAmbientOcclusionCasterSettings(Simplygon::spAmbientOcclusionCasterSettings InAmbientOcclusionCasterSettings, const FAmbientOcclusionCasterSettings& Settings) const
    {
        InAmbientOcclusionCasterSettings->SetMaterialChannel(TCHAR_TO_ANSI(*Settings.MaterialChannel));
        InAmbientOcclusionCasterSettings->SetOpacityChannelComponent((Simplygon::EColorComponent)Settings.OpacityChannelComponent);
        InAmbientOcclusionCasterSettings->SetDitherType((Simplygon::EDitherPatterns)Settings.DitherType);
        InAmbientOcclusionCasterSettings->SetFillMode((Simplygon::EAtlasFillMode)Settings.FillMode);
        InAmbientOcclusionCasterSettings->SetOpacityChannel(TCHAR_TO_ANSI(*Settings.OpacityChannel));
        InAmbientOcclusionCasterSettings->SetUseMultisampling(Settings.UseMultisampling);
        InAmbientOcclusionCasterSettings->SetRaysPerPixel(Settings.RaysPerPixel);
        InAmbientOcclusionCasterSettings->SetOutputImageFileFormat((Simplygon::EImageOutputFormat)Settings.OutputImageFileFormat);
        InAmbientOcclusionCasterSettings->SetOutputDDSCompressionType((Simplygon::EDDSCompressionType)Settings.OutputDDSCompressionType);
        InAmbientOcclusionCasterSettings->SetDilation(Settings.Dilation);
        InAmbientOcclusionCasterSettings->SetOcclusionFalloff(Settings.OcclusionFalloff);
        InAmbientOcclusionCasterSettings->SetOutputPixelFormat((Simplygon::EPixelFormat)Settings.OutputPixelFormat);
        InAmbientOcclusionCasterSettings->SetOcclusionMultiplier(Settings.OcclusionMultiplier);
        InAmbientOcclusionCasterSettings->SetUseSimpleOcclusionMode(Settings.UseSimpleOcclusionMode);
    }
#endif

};

UCLASS(BlueprintType, Blueprintable)
class SIMPLYGONUOBJECTS_API USimplygonGeometryDataCaster : public USimplygonMaterialCaster
{
    GENERATED_BODY()

public:

    UPROPERTY(EditAnywhere, BlueprintReadWrite,Category = "Geometry Data Caster Settings")
    FGeometryDataCasterSettings GeometryDataCasterSettings;

    USimplygonGeometryDataCaster() :
        GeometryDataCasterSettings()
    {
    }

#if ALLOW_SIMPLYGON
    virtual Simplygon::spMaterialCaster CreateMaterialCaster(Simplygon::ISimplygon* simplygon) override
    {
        Simplygon::spGeometryDataCaster GeometryDataCaster = simplygon->CreateGeometryDataCaster();

        Simplygon::spGeometryDataCasterSettings MaterialCasterGeometryDataCasterSettings = GeometryDataCaster->GetGeometryDataCasterSettings();
        GeometryDataCasterSettings.UpdateSettings();
        SetGeometryDataCasterSettings(MaterialCasterGeometryDataCasterSettings, GeometryDataCasterSettings);

        return GeometryDataCaster;
    }

#endif


private:
#if ALLOW_SIMPLYGON
    void SetGeometryDataCasterSettings(Simplygon::spGeometryDataCasterSettings InGeometryDataCasterSettings, const FGeometryDataCasterSettings& Settings) const
    {
        InGeometryDataCasterSettings->SetMaterialChannel(TCHAR_TO_ANSI(*Settings.MaterialChannel));
        InGeometryDataCasterSettings->SetOpacityChannelComponent((Simplygon::EColorComponent)Settings.OpacityChannelComponent);
        InGeometryDataCasterSettings->SetDitherType((Simplygon::EDitherPatterns)Settings.DitherType);
        InGeometryDataCasterSettings->SetFillMode((Simplygon::EAtlasFillMode)Settings.FillMode);
        InGeometryDataCasterSettings->SetOpacityChannel(TCHAR_TO_ANSI(*Settings.OpacityChannel));
        InGeometryDataCasterSettings->SetUseMultisampling(Settings.UseMultisampling);
        InGeometryDataCasterSettings->SetGeometryDataFieldType((Simplygon::EGeometryDataFieldType)Settings.GeometryDataFieldType);
        InGeometryDataCasterSettings->SetOutputImageFileFormat((Simplygon::EImageOutputFormat)Settings.OutputImageFileFormat);
        InGeometryDataCasterSettings->SetOutputDDSCompressionType((Simplygon::EDDSCompressionType)Settings.OutputDDSCompressionType);
        InGeometryDataCasterSettings->SetDilation(Settings.Dilation);
        InGeometryDataCasterSettings->SetGeometryDataFieldIndex(Settings.GeometryDataFieldIndex);
        InGeometryDataCasterSettings->SetOutputPixelFormat((Simplygon::EPixelFormat)Settings.OutputPixelFormat);
        InGeometryDataCasterSettings->SetMappingLayerIndex(Settings.MappingLayerIndex);
        InGeometryDataCasterSettings->SetMappingInf((float*)&Settings.MappingInf);
        InGeometryDataCasterSettings->SetMappingSup((float*)&Settings.MappingSup);
    }
#endif

};

UCLASS(BlueprintType, Blueprintable)
class SIMPLYGONUOBJECTS_API USimplygonVertexColorCaster : public USimplygonMaterialCaster
{
    GENERATED_BODY()

public:

    UPROPERTY(EditAnywhere, BlueprintReadWrite,Category = "Vertex Color Caster Settings")
    FVertexColorCasterSettings VertexColorCasterSettings;

    USimplygonVertexColorCaster() :
        VertexColorCasterSettings()
    {
    }

#if ALLOW_SIMPLYGON
    virtual Simplygon::spMaterialCaster CreateMaterialCaster(Simplygon::ISimplygon* simplygon) override
    {
        Simplygon::spVertexColorCaster VertexColorCaster = simplygon->CreateVertexColorCaster();

        Simplygon::spVertexColorCasterSettings MaterialCasterVertexColorCasterSettings = VertexColorCaster->GetVertexColorCasterSettings();
        SetVertexColorCasterSettings(MaterialCasterVertexColorCasterSettings, VertexColorCasterSettings);

        return VertexColorCaster;
    }

#endif


private:
#if ALLOW_SIMPLYGON
    void SetVertexColorCasterSettings(Simplygon::spVertexColorCasterSettings InVertexColorCasterSettings, const FVertexColorCasterSettings& Settings) const
    {
        InVertexColorCasterSettings->SetMaterialChannel(TCHAR_TO_ANSI(*Settings.MaterialChannel));
        InVertexColorCasterSettings->SetOpacityChannelComponent((Simplygon::EColorComponent)Settings.OpacityChannelComponent);
        InVertexColorCasterSettings->SetDitherType((Simplygon::EDitherPatterns)Settings.DitherType);
        InVertexColorCasterSettings->SetFillMode((Simplygon::EAtlasFillMode)Settings.FillMode);
        InVertexColorCasterSettings->SetOpacityChannel(TCHAR_TO_ANSI(*Settings.OpacityChannel));
        InVertexColorCasterSettings->SetUseMultisampling(Settings.UseMultisampling);
        InVertexColorCasterSettings->SetOutputColorLevel(Settings.OutputColorLevel);
        InVertexColorCasterSettings->SetOutputImageFileFormat((Simplygon::EImageOutputFormat)Settings.OutputImageFileFormat);
        InVertexColorCasterSettings->SetOutputDDSCompressionType((Simplygon::EDDSCompressionType)Settings.OutputDDSCompressionType);
        InVertexColorCasterSettings->SetDilation(Settings.Dilation);
        InVertexColorCasterSettings->SetOutputColorName(TCHAR_TO_ANSI(*Settings.OutputColorName));
        InVertexColorCasterSettings->SetOutputPixelFormat((Simplygon::EPixelFormat)Settings.OutputPixelFormat);
        InVertexColorCasterSettings->SetColorSpaceEdgeThreshold(Settings.ColorSpaceEdgeThreshold);
    }
#endif

};

